Notebook to make the panels for the paper figures after revision

General Setup

Setup chunk

Load libraries

knitr::opts_chunk$set(fig.width = 8)
knitr::opts_knit$set(root.dir = normalizePath(".."))
knitr::opts_knit$get("root.dir")
[1] "/nas/groups/treutlein/USERS/tomasgomes/projects/liver_regen"

Define plot theme(s)

library(dplyr)

Attaching package: ‘dplyr’

The following objects are masked from ‘package:stats’:

    filter, lag

The following objects are masked from ‘package:base’:

    intersect, setdiff, setequal, union
library(Seurat)
Registered S3 method overwritten by 'htmlwidgets':
  method           from         
  print.htmlwidget tools:rstudio
Registered S3 method overwritten by 'spatstat.geom':
  method     from
  print.boxx cli 
Attaching SeuratObject
library(ggplot2)
library(ggrepel)
library(ggridges)
library(pheatmap)
library(RColorBrewer)
library(MetBrewer)

Useful functions

th_gen = theme(axis.text = element_text(size = 7, colour = "black"),
               axis.title = element_text(size = 8, colour = "black"),
               axis.line = element_line(colour = "black"),
               plot.background = element_blank(),
               axis.ticks = element_blank(), 
               panel.background = element_blank(),
               panel.grid = element_blank(),
               legend.background = element_blank(), 
               legend.key.size = unit(0.35, "cm"),
               legend.key = element_blank(), legend.spacing = unit(0.7, "cm"),
               legend.text = element_text(size = 9),
               legend.title = element_text(size = 10),
               legend.box.margin = margin(0.1,0.1,0.1,0.1),
               legend.box.spacing = unit(0.5,"cm"))
pointsize = 0.3
theme_set(th_gen)

Colour palettes

breakStr = function(s, n = 20) {return(gsub(paste0('(.{1,',as.character(n),'})(\\s|$)'), '\\1\n', s))}

getTopTerms = function(godf, topt = 100, ncl = 5, nt = 2){
  topt = if(nrow(godf)<topt) nrow(godf) else topt
  if(nrow(godf)<ncl) return(godf)
  df = godf[1:topt,]
  genes = sapply(df$geneID, function(x) strsplit(x, "/"))
  resmat = matrix(0, length(genes), length(genes))
  for(i in 1:length(genes)){
    for(j in 1:length(genes)){
      resmat[i,j] = length(intersect(genes[[i]], genes[[j]]))/length(genes[[i]])
    }
  }
  cl = hclust(dist(resmat), method = "ward.D2")
  cl = cutree(cl, ncl)
  res_df = data.frame("Description" = df$Description, "qvalue" = df$qvalue, cl, 
                      "geneID" = unlist(df$geneID), stringsAsFactors = F)
  res_df = res_df[order(res_df$qvalue, decreasing = F),]
  topterms = unlist(tapply(res_df$Description, res_df$cl, function(x) x[1:nt]))
  res_df = res_df[res_df$Description %in% topterms,]
  
  return(res_df)
}

getTopTermsPaired = function(godf, genescol = "genes_all", ncl = 5, nt = 2){
  if(nrow(godf)<ncl) return(godf)
  genes = sapply(godf[,genescol], function(x) strsplit(x, "/"))
  resmat = matrix(0, length(genes), length(genes))
  for(i in 1:length(genes)){
    for(j in 1:length(genes)){
      resmat[i,j] = length(intersect(genes[[i]], genes[[j]]))/length(genes[[i]])
    }
  }
  cl = hclust(dist(resmat), method = "ward.D2")
  cl = cutree(cl, ncl)
  res_df = data.frame("Description" = godf$Description, "qval_embolized" = godf$qval_embolized, 
                      "qval_regenerating" = godf$qval_regenerating, 
                      "genes_embolized" = unlist(godf$genes_embolized), 
                      "genes_regenerating" = unlist(godf$genes_regenerating),
                      cl, stringsAsFactors = F)
  res_df$qval_max = apply(res_df[,c("qval_embolized","qval_regenerating")], 1, function(x) min(x))
  res_df = res_df[order(res_df$qval_max, decreasing = F),]
  topterms = unlist(tapply(res_df$Description, res_df$cl, function(x) x[1:nt]))
  res_df = res_df[res_df$Description %in% topterms,]
  
  return(res_df)
}

rpfilter = function(x){
  return(!grepl("^RPL", x$geneID) & !grepl("^RPS", x$geneID) & 
           !grepl("/RPL", x$geneID, fixed = T) & !grepl("/RPS", x$geneID, fixed = T))
}

Figure 1

Main Figure

UMAP with all cell types

colsmajor = c("Cholangiocytes" = "bisque2", "Endothelial" = "aquamarine4",  
              "Hepatocytes" = "tomato3", "Immune" = "skyblue", 
              "Mesenchymal" = "sandybrown", "Doublets" = "grey90")
colcond = c("healthy" = "orange", "regenerating" = "salmon", 
            "embolised" = "darkred", "embolized" = "darkred")
coldon = c("sc_H1" = "plum4", "sc_H2" = "salmon4", "sc_H3" = "lightsalmon3")
coldonall = c("sc_H1" = "plum4", "sc_H2" = "salmon4", "sc_H3" = "lightsalmon3", 
              "sc_E1" = "darkorange3", "sc_R1" = "darkorange3", "sc_E2" = "goldenrod3", 
              "sc_R2" = "goldenrod3",  "sc_E3" = "mediumorchid", "sc_R3" = "mediumorchid", 
              "sc_E4" = "plum2", "sc_R4" = "plum2", "sc_E5" = "palevioletred3", 
              "sc_R5" = "palevioletred3", "sc_E6" = "peachpuff2", "sc_R6" = "peachpuff2",
              "sc_E1/sc_R1" = "darkorange3", "sc_E2/sc_R2" = "goldenrod3", 
              "sc_E3/sc_R3" = "mediumorchid", "sc_E4/sc_R4" = "plum2", 
              "sc_E5/sc_R5" = "palevioletred3", "sc_E6/sc_R6" = "peachpuff2")

colsallct = c("Cholangiocytes" = "bisque2", "Hepatocytes" = "tomato3", "Stellate cells" = "sandybrown", 
              "Doublets" = "grey90", "LSEC pericentral" = "aquamarine4", "LSEC periportal" = "aquamarine2", 
              "Endothelial cells (non-LSEC)" = "forestgreen", "Plasmablasts" = "darkorchid4",
              "Kupffer cells" = "skyblue1", "ab-T cells" = "lightskyblue3", "gd-T cells" = "cornflowerblue",
              "B cells" = "darkorchid1", "cDCs" = "deepskyblue1", "pDCs" = "royalblue3", 
              "Macrophages" = "steelblue3", "Dividing cells" = "grey35", "LSEC" = "aquamarine3")
colsub = c("rosybrown4","thistle4","thistle3","aquamarine4","aquamarine3",
           "forestgreen","tomato4","tomato3","darksalmon","skyblue",
           "cadetblue","sandybrown","palegoldenrod")
colsmidct = c("Cholangiocytes" = "bisque2", "Hepatocytes" = "tomato3", 
              "Mesenchymal" = "sandybrown", "pDCs" = "royalblue3", 
              "T cells" = "lightskyblue3", "LSEC" = "aquamarine3",
              "other ECs" = "forestgreen", "B cells" = "darkorchid1",
              "Kupffer cells" = "skyblue1", "other Mono-Mac" = "steelblue3", 
              "ILC" = "slateblue1")
plot_df = data.frame(hcells_css@reductions$umap_css@cell.embeddings)
plot_df$names_major = as.character(hcells_css@meta.data$names_major)
plot_df$names_major[plot_df$names_major=="T cells" | 
                      plot_df$names_major=="B cells" | 
                      plot_df$names_major=="Macrophages" |
                      plot_df$names_major=="DCs"] = "Immune"
plot_df$names_major[plot_df$names_major=="Stellate cells"] = "Mesenchymal"
plot_df$names_major[plot_df$names_major=="Endothelial cells"] = "Endothelial"
plt = ggplot(plot_df, aes(x = UMACSS_1, y = UMACSS_2, colour = names_major))+
  geom_point(size = pointsize)+
  guides(colour = guide_legend(override.aes = list(size = 3), title = "Cell Type"))+
  scale_colour_manual(values = colsmajor)+
  theme_classic()+
  th_gen+
  theme(axis.line = element_blank(),
        axis.ticks = element_blank(),
        axis.title = element_blank(),
        axis.text = element_blank(),
        legend.title = element_text(hjust = 0),
        aspect.ratio = 1)

pdf("figure_panels/fig1/umap_fresh_major.pdf", 
    useDingbats = F, height = 4, width = 5)
print(plt)
dev.off()
png("figure_panels/fig1/umap_fresh_major.png", 
    height=8, width=8, unit="cm", res=600, antialias = "subpixel")
print(plt)
dev.off()
pdf("figure_panels/fig1/umap_fresh_major_noLeg.pdf", 
    useDingbats = F, height = 4, width = 5)
print(plt+theme(legend.position = "none"))
dev.off()
png("figure_panels/fig1/umap_fresh_major_noLeg.png", 
    height=8, width=8, unit="cm", res=600, antialias = "subpixel")
print(plt+theme(legend.position = "none"))

UMAP with healthy donors

plot_df = data.frame(hcells_css@reductions$umap_css@cell.embeddings)
plot_df$Donor = factor(hcells_css@meta.data$Donor)
plot_df$Donor = plyr::revalue(plot_df$Donor, c("HD1" = "sc_H1", "HD2" = "sc_H2", "HD3" = "sc_H3"))

plt = ggplot(plot_df[sample(1:nrow(plot_df), nrow(plot_df), replace = F),], 
             aes(x = UMACSS_1, y = UMACSS_2, colour = Donor))+
  geom_point(size = pointsize)+
  guides(colour = guide_legend(override.aes = list(size = 3), title = "Donors"))+
  scale_colour_manual(values = coldon)+
  theme_classic()+
  th_gen+
  theme(axis.line = element_blank(),
        axis.ticks = element_blank(),
        axis.title = element_blank(),
        axis.text = element_blank(),
        legend.title = element_text(hjust = 0),
        aspect.ratio = 1)

pdf("figure_panels/fig1/umap_fresh_donors.pdf", 
    useDingbats = F, height = 4, width = 5)
print(plt)
dev.off()
png("figure_panels/fig1/umap_fresh_donors.png", 
    height=8, width=8, unit="cm", res=600, antialias = "subpixel")
print(plt)
dev.off()
pdf("figure_panels/fig1/umap_fresh_donors_noLeg.pdf", 
    useDingbats = F, height = 4, width = 5)
print(plt+theme(legend.position = "none"))
dev.off()
png("figure_panels/fig1/umap_fresh_donors_noLeg.png", 
    height=8, width=8, unit="cm", res=600, antialias = "subpixel")
print(plt+theme(legend.position = "none"))
dev.off()

Violins for cell type markers

markers = c("ASGR1", "APOB", "APOC3",
            "KRT7","CLDN4","EPCAM",
            "CLEC4G","PECAM1","CD36",
            "DCN","COLEC11","ACTA2",
            "PTPRC","HLA-DQA1","LYZ")
exp_mk = data.frame(Matrix::t(hcells_css@assays$SCT@data[markers,]))
plot_df = cbind(exp_mk, 
                data.frame(names_major = as.character(hcells_css@meta.data[,c("names_major")]), 
                           stringsAsFactors = F))
plot_df$names_major[plot_df$names_major=="T cells" | 
                      plot_df$names_major=="B cells" | 
                      plot_df$names_major=="Macrophages" | 
                      plot_df$names_major=="DCs"] = "Immune"
plot_df$names_major[plot_df$names_major=="Endothelial cells"] = "Endothelial"
plot_df$names_major[plot_df$names_major=="Stellate cells"] = "Mesenchymal"
plot_df = plot_df[plot_df$names_major!="Doublets",]
plot_df$names_major = factor(plot_df$names_major, 
                             levels = c("Hepatocytes", "Cholangiocytes", "Endothelial", "Mesenchymal",
                                        "Immune"))
plot_df = reshape2::melt(plot_df)
plot_df$variable = factor(gsub(".", "-", plot_df$variable, fixed = T), levels = markers)

vio_mk = ggplot(plot_df, aes(x = names_major, y = value, fill = names_major))+
  facet_grid(variable~names_major, scales = "free")+
  geom_violin(scale = "width", size = 0.3)+
  scale_y_continuous(breaks = seq(0,10,2), labels = seq(0,10,2), name = "log(exp+1)")+
  scale_fill_manual(values = colsmajor)+
  theme(strip.background.y = element_blank(),
        strip.background.x = element_rect(fill = "transparent", 
                                          colour = "black", size = 0.8),
        strip.text.y = element_text(angle = 0, size = 6.5, colour = "black", face = "bold"),
        strip.text.x = element_text(face = "bold", size = 6.5, colour = "black"),
        legend.position = "none",
        axis.text.x = element_blank(),
        axis.title.x = element_blank(), 
        axis.line.x.bottom = element_blank())

pdf("figure_panels/fig1/violin_markers_major.pdf", 
    useDingbats = F, height = 5, width = 5.5)
print(vio_mk)
dev.off()
png("figure_panels/fig1/violin_markers_major.png", height = 425, width = 450, antialias = "subpixel")
print(vio_mk)
dev.off()

Heatmap for major cell types

# removed HHIP
nmg=c("PDGFRA","CALD1","COL6A1","PDGFRB",
      "CSF1R","CD163","MARCO","CD69","IL7R","PCK1","CYP2A7","CYP3A4","CRP",
      "ROBO4","EGFL7","CLEC4M","FCN2","KRT7","CFTR","ONECUT1")
plot_df = data.frame(row.names = rownames(hcells_css@meta.data),
                     names_major = as.character(hcells_css@meta.data[,c("names_major")]),
                     donor = as.character(hcells_css@meta.data[,c("Donor")]),
                     stringsAsFactors = F) 
plot_df$names_major[plot_df$names_major=="T cells" | 
                      plot_df$names_major=="B cells" | 
                      plot_df$names_major=="Macrophages" | 
                      plot_df$names_major=="DCs"] = "Immune"
plot_df$names_major[plot_df$names_major=="Endothelial cells"] = "Endothelial"
plot_df$names_major[plot_df$names_major=="Stellate cells"] = "Mesenchymal"
plot_df = plot_df[plot_df$names_major!="Doublets",]
plot_df = plot_df[order(plot_df$names_major),]
m1=GetAssayData(hcells_css, slot="data")[nmg,rownames(plot_df)]
m1 = t(apply(m1, 1, scale, scale = F))
colnames(m1)=rep("",ncol(m1))
coul <- colorRampPalette(brewer.pal(9, "Greys"))(100)[-c(1:5)]
m1[m1>1] = 1
#m1[m1<=(-2)] = -2
heatmap(m1,Rowv = NA,Colv = NA, col=coul)

Violins for all cell types

exp_mk = data.frame(Matrix::t(hcells_css@assays$SCT@data[markers,]))
plot_df = cbind(exp_mk, 
                hcells_css@meta.data[,c("names_major","names_clusters")])
plot_df$names_major = as.character(plot_df$names_major)
plot_df$names_major[plot_df$names_major=="T cells" | 
                      plot_df$names_major=="B cells" | 
                      plot_df$names_major=="Macrophages" | 
                      plot_df$names_major=="DCs"] = "Immune"
plot_df$names_major[plot_df$names_major=="Endothelial cells"] = "Endothelial"
plot_df$names_major[plot_df$names_major=="Stellate cells"] = "Mesenchymal"
plot_df = plot_df[plot_df$names_major!="Doublets",]
plot_df$names_major = factor(plot_df$names_major, 
                             levels = c("Hepatocytes", "Cholangiocytes", "Endothelial", "Mesenchymal",
                                        "Immune"))
plot_df = reshape2::melt(plot_df)
plot_df$variable = factor(gsub(".", "-", plot_df$variable, fixed = T), levels = markers)

ggplot(plot_df, aes(x = names_clusters, y = value, fill = names_clusters))+
  facet_grid(variable~names_major, scales = "free")+
  geom_violin(scale = "width")+
  scale_y_continuous(breaks = seq(0,10,2), labels = seq(0,10,2), name = "log(exp+1)")+
  #scale_fill_manual(values = colsmajor)+
  theme(strip.background.y = element_blank(),
        strip.background.x = element_rect(fill = "transparent", 
                                          colour = "black", size = 0.8),
        strip.text.y = element_text(angle = 0, size = 6.5, colour = "black", face = "bold"),
        strip.text.x = element_text(face = "bold", size = 6.5, colour = "black"),
        legend.position = "none",
        axis.text.x = element_text(angle = -35, hjust = 0, vjust = 0.1),
        axis.line.x.bottom = element_blank())

Cell type proportions

plot_df = data.frame("names_major" = as.character(hcells_css@meta.data$names_major),
                     "Donor" = as.character(hcells_css@meta.data$Donor),
                     stringsAsFactors = F)
plot_df$names_major[plot_df$names_major=="T cells" | 
                      plot_df$names_major=="B cells" | 
                      plot_df$names_major=="Macrophages" | 
                      plot_df$names_major=="DCs"] = "Immune"
plot_df$names_major[plot_df$names_major=="Endothelial cells"] = "Endothelial"
plot_df$names_major[plot_df$names_major=="Stellate cells"] = "Mesenchymal"
plot_df = plot_df[plot_df$names_major!="Doublets",]
cnts_ct = table(plot_df$names_major, plot_df$Donor)
plot_df = reshape2::melt(apply(cnts_ct, 1, function(x) x/sum(x)))
#plot_df$Var2 = factor(plot_df$Var2, 
#                      levels = c("Hepatocytes", "Cholangiocytes", "Endothelial","Mesenchymal", "Immune"))
plot_df$Var1 = plyr::revalue(plot_df$Var1, c("HD1" = "sc_H1", "HD2" = "sc_H2", "HD3" = "sc_H3"))
plot_df$Var1 = factor(plot_df$Var1, levels = rev(levels(plot_df$Var1)))

plt = ggplot(plot_df, aes(x = Var2, y = value*100, fill = Var1))+
  geom_bar(stat = "identity")+
  scale_y_continuous(expand = c(0,0))+
  scale_fill_manual(values = coldon)+
  labs(y = "Cell type proportion [%]", x = NULL)+
  theme_classic()+
  th_gen+
  theme(axis.line.x = element_blank(),
        axis.ticks.y = element_line(),
        axis.ticks.x = element_blank())

pdf("figure_panels/fig1/proportions_fresh_major_donor.pdf", 
    useDingbats = F, height = 4, width = 5)
print(plt)
dev.off()
png("figure_panels/fig1/proportions_fresh_major_donor.png", 
    height = 325, width = 400, antialias = "subpixel")
print(plt)
dev.off()
pdf("figure_panels/fig1/proportions_fresh_major_donor_noLeg.pdf", 
    useDingbats = F, height = 4, width = 5)
print(plt+theme(legend.position = "none"))
dev.off()
png("figure_panels/fig1/proportions_fresh_major_donor_noLeg.png", 
    height = 325, width = 400, antialias = "subpixel")
print(plt+theme(legend.position = "none"))
dev.off()

Import markers

markers = c("ASGR1", "APOB", "APOC3", "CYP2E1", "HAMP", "ORM1", "SAA1", "NNMT", "FABP1", "MT1G", "ORM2", "TTR", "HP", "APOC1", "APOA2","FGB","CYP3A4","CPS1","ARG1","SAA2",# Hep
            "KRT7","CLDN4","EPCAM", "TACSTD2", "CD24", "KRT19", "ANXA4", "CXCL6", "FXYD2", "SOX4",  "CRYAB","DEFB1","SLC12A2","MMP7","TNFRSF12A","CXCL1","BICC1","S100A14","DCDC2","PLPP2",# Cho
            "CLEC4G","PECAM1","CD36", "FCN3", "DNASE1L3", "CLEC1B", "CRHBP", "AKAP12", "IFI27", "GNG11", "IL33","FLT1","PRSS23","ENG","RAMP3","F8","VWF","CLDN5","CCL14","LYVE1",# End
            "DCN","COLEC11","ACTA2", "CCL2", "TAGLN", "IGFBP3", "BGN", "LUM", "COL3A1", "MYL9", "TPM2","AEBP1","GGT5","ASPN","COL14A1","PTGDS","COL6A1","CYR61","COLEC10","CXCL12",# Mes
            "PTPRC","HLA-DQA1","LYZ", "LILRB2", "MARCO", "C1QB", "FCGR3A",  "NKG7", "MS4A1", "MZB1", "CCL5","KLRD1","AREG","MS4A7","AXL","CD69","GPR183","TLR2","CD44","IL7R") # Imm
mk_list = list("Hepatocytes" = markers[1:10], "Cholangiocytes" = markers[21:30], 
               "Endothelial" = markers[41:50], "Mesenchymal" = markers[61:70], "Immune" = markers[81:90])

cell_type_mk = readRDS(file = "results/integr_allcells/cell_type_mk_major.RDS")
fresh_de = list()
for(n in unique(cell_type_mk$major_all$cluster)){
  fresh_de[[n]] = cell_type_mk$major_all[cell_type_mk$major_all$cluster==n,]
}

load("data/processed/received_Aga/DE_tables_celltype_frozenSCT.rdata")
frozen_de = list("Cholangiocytes" = cell_type_mk_cho, "Hepatocytes" = cell_type_mk_hep, 
                 "Endothelial" = cell_type_mk_ec, "Immune" = cell_type_mk_imm, 
                 "Mesenchymal" = cell_type_mk_mes)
for(n in names(frozen_de)){
  frozen_de[[n]]$cluster = n
  frozen_de[[n]]$gene = rownames(frozen_de[[n]])
}

both_list = list()
top_mk = list()
for(n in names(fresh_de)){
  both_DE = merge(fresh_de[[n]], frozen_de[[n]], by = "gene", all = T)[,c(1,3,6,9,12)]
  colnames(both_DE) = c("gene", "FC_fresh", "pval_fresh", "FC_frozen", "pval_frozen")
  both_DE$FC_fresh[is.na(both_DE$FC_fresh)] = 0
  both_DE$pval_fresh[is.na(both_DE$pval_fresh)] = 1
  both_DE$FC_frozen[is.na(both_DE$FC_frozen)] = 0
  both_DE$pval_frozen[is.na(both_DE$pval_frozen)] = 1
  both_DE$celltype = n
  both_DE$s = both_DE$FC_fresh+both_DE$FC_frozen
  both_DE = both_DE[order(both_DE$s, decreasing = T),]
  cond_fc = both_DE$FC_fresh>=0.1 & both_DE$FC_frozen>=0.1
  cond_pv = both_DE$pval_fresh<=0.05 | both_DE$pval_frozen<=0.05
  both_DE$iscol = ifelse(cond_fc & cond_pv, 
                         ifelse(both_DE$gene %in% mk_list[[n]], "istop", "isDE"), "notDE")
  both_DE$iscol = factor(both_DE$iscol, levels = rev(c("istop", "isDE", "notDE")))
  both_DE$istop = both_DE$gene %in% mk_list[[n]]#[1:3]
  both_list[[n]] = both_DE
  top_mk[[n]] = both_DE$gene[cond_fc & cond_pv][1:20]
}
top_mk = top_mk[c(4,1,3,5,2)]

Heatmap per cluster

cell_type_mk = readRDS(file = "results/cond_effect/cell_type_mk.RDS")
# cut markers here depending on the size you want for heatmap, then adjust figure
markers = c("ASGR1", "APOB", "APOC3", "CYP2E1", "HAMP", "ORM1", "SAA1", "NNMT", "FABP1", "MT1G", "ORM2", "TTR", "HP", "APOC1", "APOA2","FGB","CYP3A4","CPS1","ARG1","SAA2",# Hep
            "KRT7","CLDN4","EPCAM", "TACSTD2", "CD24", "KRT19", "ANXA4", "CXCL6", "FXYD2", "SOX4",  "CRYAB","DEFB1","SLC12A2","MMP7","TNFRSF12A","CXCL1","BICC1","S100A14","DCDC2","PLPP2",# Cho
            "CLEC4G","PECAM1","CD36", "FCN3", "DNASE1L3", "CLEC1B", "CRHBP", "AKAP12", "IFI27", "GNG11", "IL33","FLT1","PRSS23","ENG","RAMP3","F8","VWF","CLDN5","CCL14","LYVE1",# End
            "DCN","COLEC11","ACTA2", "CCL2", "TAGLN", "IGFBP3", "BGN", "LUM", "COL3A1", "MYL9", "TPM2","AEBP1","GGT5","ASPN","COL14A1","PTGDS","COL6A1","CYR61","COLEC10","CXCL12",# Mes
            "PTPRC","HLA-DQA1","LYZ", "LILRB2", "MARCO", "C1QB", "FCGR3A",  "NKG7", "MS4A1", "MZB1", "CCL5","KLRD1","AREG","MS4A7","AXL","CD69","GPR183","TLR2","CD44","IL7R") # Imm
markers_topboth = unlist(top_mk)
markers = markers_topboth

load("data/processed/received_Aga/mean_exp_celltype_frozen.rdata")
hcells_css@meta.data$major_ct = as.character(hcells_css@meta.data$names_major)
hcells_css@meta.data$major_ct[hcells_css@meta.data$major_ct=="T cells" | 
                      hcells_css@meta.data$major_ct=="B cells" | 
                      hcells_css@meta.data$major_ct=="Macrophages" |
                      hcells_css@meta.data$major_ct=="DCs"] = "Immune"
hcells_css@meta.data$major_ct[hcells_css@meta.data$major_ct=="Stellate cells"] = "Mesenchymal"
hcells_css@meta.data$major_ct[hcells_css@meta.data$major_ct=="Endothelial cells"] = "Endothelial"
m_ct_fresh = apply(as.matrix(hcells_css@assays$SCT@data), 1, 
                   function(x) tapply(x, hcells_css@meta.data$major_ct, mean))

m_ct_frozen = t(m_ct_frozen)
m_ct_frozen = t(apply(m_ct_frozen, 1, scale))
colnames(m_ct_frozen) = rownames(m_ct_fresh)[-2]
m_ct_fresh = t(m_ct_fresh)[,-2]
m_ct_fresh = t(apply(m_ct_fresh, 1, scale))
colnames(m_ct_fresh) = colnames(m_ct_frozen)

mean_ct = merge(m_ct_fresh, m_ct_frozen, by = 0)
rownames(mean_ct) = mean_ct[,1]
mean_ct = mean_ct[,-1]
colnames(mean_ct) = paste0(rep(colnames(m_ct_fresh), 2), rep(c("_fresh", "_frozen"), each = 5))

hcl = hclust(dist(t(mean_ct)), method = "ward.D2")
plot(hcl)

annot_df = data.frame(row.names = colnames(mean_ct),
                      "cell type" = unlist(lapply(strsplit(colnames(mean_ct), "_"), function(x) x[1])),
                      "processing" = unlist(lapply(strsplit(colnames(mean_ct), "_"), function(x) x[2])))

callback = function(hc, mat){
  sv = svd(t(mat))$v[,2]
    dend = reorder(as.dendrogram(hc), c(1:4,))
    as.hclust(dend)
}

pdf("figure_panels/fig1/major_celltypes_heatmap_freshfrozen_10.pdf", 
    useDingbats = F, height = 7.5, width = 6)
heat = pheatmap::pheatmap(mean_ct[markers[c(41:50, 61:70, 81:90,  1:10, 21:30)],], 
                          clustering_method = "ward.D2", treeheight_row = 0, annotation_col = annot_df,
                          cluster_rows = F, treeheight_col = 20, fontsize_row = 5.5,
                          annotation_colors = list("processing" = c("fresh" = "#d4d4d4", 
                                                                    "frozen" = "#5d5d5d"),
                                                   "cell.type" = colsmajor[-6]),
                          show_colnames = F, 
                          color = colorRampPalette(rev(brewer.pal(n = 9, name = "RdBu")))(100))
dev.off()

FC fresh vs frozen

mk_list = list("Hepatocytes" = markers[1:10], "Cholangiocytes" = markers[21:30], 
               "Endothelial" = markers[41:50], "Mesenchymal" = markers[61:70], "Immune" = markers[81:90])

plt_fc_list = list()
pdf("figure_panels/fig1/major_celltypes_FCscatter_10.pdf", 
    useDingbats = F, height = 5, width = 4.5)
for(n in names(both_list)){
  both_DE = both_list[[n]]
  cc = cor(both_DE$FC_fresh, both_DE$FC_frozen)
  both_DE = both_DE[order(both_DE$iscol),]
  
  cols_use = c("istop" = unname(colsmajor[n]), "isDE" = "grey35", "notDE" = "grey85")
  plt = ggplot(both_DE, aes(x = FC_fresh, y = FC_frozen, colour = iscol))+
    geom_vline(xintercept = 0, colour = "grey40")+
    geom_hline(yintercept = 0, colour = "grey40")+
    geom_point()+
    geom_text_repel(data = both_DE[both_DE$istop & both_DE$iscol=="istop",], mapping = aes(label = gene),
                    fontface = "bold")+
    theme_bw()+
    scale_colour_manual(values = cols_use)+
    labs(title = n, subtitle = paste0("PCC = ", round(cc, 2)))+
    theme(aspect.ratio = 1,
          axis.text = element_text(colour = "black"),
          legend.position = "none", 
          panel.grid = element_blank())
  
  plt_fc_list[[n]] = plt
  print(plt)
}
dev.off()

Expression comparison fresh vs frozen

load("data/processed/received_Aga/mean_exp_celltype_frozenCOUNTS.rdata")
hcells_css@meta.data$major_ct = as.character(hcells_css@meta.data$names_major)
hcells_css@meta.data$major_ct[hcells_css@meta.data$major_ct=="T cells" | 
                      hcells_css@meta.data$major_ct=="B cells" | 
                      hcells_css@meta.data$major_ct=="Macrophages" |
                      hcells_css@meta.data$major_ct=="DCs"] = "Immune"
hcells_css@meta.data$major_ct[hcells_css@meta.data$major_ct=="Stellate cells"] = "Mesenchymal"
hcells_css@meta.data$major_ct[hcells_css@meta.data$major_ct=="Endothelial cells"] = "Endothelial"
m_ct_fresh = apply(as.matrix(hcells_css@assays$SCT@counts), 1, 
                   function(x) tapply(x, hcells_css@meta.data$major_ct, mean))

m_ct_frozen = log(t(m_ct_frozen.counts))
#m_ct_frozen = t(apply(m_ct_frozen, 1, scale))
colnames(m_ct_frozen) = rownames(m_ct_fresh)[-2]
m_ct_fresh = log(t(m_ct_fresh)[,-2])
#m_ct_fresh = t(apply(m_ct_fresh, 1, scale))
colnames(m_ct_fresh) = colnames(m_ct_frozen)

mean_ct = merge(m_ct_fresh, m_ct_frozen, by = 0)
rownames(mean_ct) = mean_ct[,1]
mean_ct = mean_ct[,-1]
colnames(mean_ct) = paste0(rep(colnames(m_ct_fresh), 2), rep(c("_fresh", "_frozen"), each = 5))

par(mfrow = c(2,3))
plot(mean_ct$Cholangiocytes_fresh, mean_ct$Cholangiocytes_frozen, pch = 20, cex = 0.5, xlim = c(-8,5), ylim = c(-8,5))
title("Cholangiocytes")
abline(0,1)
plot(mean_ct$Endothelial_fresh, mean_ct$Endothelial_frozen, pch = 20, cex = 0.5, xlim = c(-8,5), ylim = c(-8,5))
title("Endothelial")
abline(0,1)
plot(mean_ct$Hepatocytes_fresh, mean_ct$Hepatocytes_frozen, pch = 20, cex = 0.5, xlim = c(-10,6), ylim = c(-10,6))
title("Hepatocytes")
abline(0,1)
plot(mean_ct$Immune_fresh, mean_ct$Immune_frozen, pch = 20, cex = 0.5, xlim = c(-8,5), ylim = c(-8,5))
title("Immune")
abline(0,1)
plot(mean_ct$Mesenchymal_fresh, mean_ct$Mesenchymal_frozen, pch = 20, cex = 0.5, xlim = c(-8,5), ylim = c(-8,5))
title("Mesenchymal")
abline(0,1)
plot(rowMeans(mean_ct[,1:5]), rowMeans(mean_ct[,6:10]), pch = 20, cex = 0.5, xlim = c(-8,5), ylim = c(-8,5))
title("All")
abline(0,1)

Supplementary

UMAP with healthy donors split

plot_df = data.frame(hcells_css@reductions$umap_css@cell.embeddings)
plot_df$Donor = factor(hcells_css@meta.data$Donor)
plot_df$Donor = plyr::revalue(plot_df$Donor, c("HD1" = "sc_H1", "HD2" = "sc_H2", "HD3" = "sc_H3"))

plt = ggplot(plot_df[sample(1:nrow(plot_df), nrow(plot_df), replace = F),], 
             aes(x = UMACSS_1, y = UMACSS_2, colour = Donor))+
  facet_wrap(~Donor)+
  geom_point(size = 0.15)+
  guides(colour = guide_legend(override.aes = list(size = 3), title = "Donors"))+
  scale_colour_manual(values = coldon)+
  theme_classic()+
  th_gen+
  theme(axis.line = element_blank(),
        axis.ticks = element_blank(),
        axis.title = element_blank(),
        axis.text = element_blank(),
        legend.title = element_text(hjust = 0),
        aspect.ratio = 1)

pdf("figure_panels/fig1/umap_fresh_donors_split.pdf", 
    useDingbats = F, height = 4, width = 7)
print(plt)
dev.off()
png("figure_panels/fig1/umap_fresh_donors_split.png", 
    height=8, width=10, unit="cm", res=600, antialias = "subpixel")
print(plt)
dev.off()
pdf("figure_panels/fig1/umap_fresh_donors_noLeg_split.pdf", 
    useDingbats = F, height = 4, width = 7)
print(plt+theme(legend.position = "none"))
dev.off()
png("figure_panels/fig1/umap_fresh_donors_noLeg_split.png", 
    height=8, width=10, unit="cm", res=600, antialias = "subpixel")
print(plt+theme(legend.position = "none"))
dev.off()

Boxplot with nUMI

plot_df = data.frame(hcells_css@reductions$umap_css@cell.embeddings)
plot_df$names_major = as.character(hcells_css@meta.data$names_major)
plot_df$names_major[plot_df$names_major=="T cells" | 
                      plot_df$names_major=="B cells" | 
                      plot_df$names_major=="Macrophages" |
                      plot_df$names_major=="DCs"] = "Immune"
plot_df$names_major[plot_df$names_major=="Stellate cells"] = "Mesenchymal"
plot_df$names_major[plot_df$names_major=="Endothelial cells"] = "Endothelial"
plot_df$nGene = hcells_css@meta.data$nFeature_SCT
plot_df = plot_df[,3:5]
saveRDS(plot_df, "./to_send/df_celltypes_umi_gene.RDS") # plotted by Aga

UMAP with all cell types

plot_df = data.frame(hcells_css@reductions$umap_css@cell.embeddings)
colnames(plot_df) = c("UMAPCSS_1", "UMAPCSS_2")
plot_df$names_major = as.character(hcells_css@meta.data$names_major)
plot_df$names_major[plot_df$names_major=="T cells" | 
                      plot_df$names_major=="B cells" | 
                      plot_df$names_major=="Macrophages" |
                      plot_df$names_major=="DCs"] = "Immune"
plot_df$names_major[plot_df$names_major=="Stellate cells"] = "Mesenchymal"
plot_df$names_major[plot_df$names_major=="Endothelial cells"] = "Endothelial"
plot_df$names_clusters = as.character(hcells_css@meta.data$names_clusters)
plot_df$names_clusters[grepl("Hepatocytes ", plot_df$names_clusters)] = "Hepatocytes"
plot_df$names_clusters[grepl("central vein", plot_df$names_clusters)] = "LSEC pericentral"
plot_df$names_clusters[grepl("portal vein", plot_df$names_clusters)] = "LSEC periportal"
plot_df$names_clusters[grepl("interaction", plot_df$names_clusters) |
                         grepl("mix", plot_df$names_clusters) ] = "Doublets"
plot_df$names_clusters = factor(plot_df$names_clusters, 
                                levels = c("Cholangiocytes", "LSEC periportal", "LSEC pericentral", 
                                           "Endothelial cells (non-LSEC)", "Hepatocytes", "Kupffer cells",
                                           "Macrophages", "cDCs", "pDCs", "ab-T cells", "gd-T cells",
                                           "B cells", "Plasmablasts",
                                           "Stellate cells", "Dividing cells", "Doublets"))

pltumap = ggplot(plot_df, aes(y = UMAPCSS_2, x = UMAPCSS_1, colour = names_clusters))+
  geom_point(size = pointsize)+
  labs(colour = "Cell Type")+
  scale_colour_manual(values = c(colsallct, "Other" = "grey88"))+
  guides(colour = guide_legend(override.aes = list(size = 2)))+
  theme(aspect.ratio = 1,
        legend.title = element_text(hjust = 0),
        axis.line = element_blank(),
        axis.text = element_blank())

pdf("figure_panels/fig1/umap_h_all_celltypes.pdf", height = 5, width = 6, useDingbats = F)
print(pltumap)
dev.off()
png("figure_panels/fig1/umap_h_all_celltypes.png", height = 325, width = 400, antialias = "subpixel")
print(pltumap)
dev.off()

plot_df$names_clusters[plot_df$names_major!="Immune"] = "Doublets"
levels(plot_df$names_clusters)[levels(plot_df$names_clusters)=="Doublets"] = "Other"
pltumap = ggplot(plot_df, aes(y = UMAPCSS_2, x = UMAPCSS_1, colour = names_clusters))+
  geom_point(size = pointsize)+
  labs(colour = "Cell Type")+
  scale_colour_manual(values = c(colsallct, "Other" = "grey88"))+
  guides(colour = guide_legend(override.aes = list(size = 2)))+
  theme(aspect.ratio = 1,
        legend.title = element_text(hjust = 0),
        axis.line = element_blank(),
        axis.text = element_blank())

Heatmap with markers for all cell types

plot_df = data.frame(hcells_css@reductions$umap_css@cell.embeddings)
colnames(plot_df) = c("UMAPCSS_1", "UMAPCSS_2")
plot_df$names_major = as.character(hcells_css@meta.data$names_major)
plot_df$names_major[plot_df$names_major=="T cells" | 
                      plot_df$names_major=="B cells" | 
                      plot_df$names_major=="Macrophages" |
                      plot_df$names_major=="DCs"] = "Immune"
plot_df$names_major[plot_df$names_major=="Stellate cells"] = "Mesenchymal"
plot_df$names_major[plot_df$names_major=="Endothelial cells"] = "Endothelial"
plot_df$names_clusters = as.character(hcells_css@meta.data$names_clusters)
plot_df$names_clusters[grepl("Hepatocytes ", plot_df$names_clusters)] = "Hepatocytes"
plot_df$names_clusters[grepl("central vein", plot_df$names_clusters)] = "LSEC pericentral"
plot_df$names_clusters[grepl("portal vein", plot_df$names_clusters)] = "LSEC periportal"
plot_df$names_clusters[grepl("interaction", plot_df$names_clusters) |
                         grepl("mix", plot_df$names_clusters) ] = "Doublets"
plot_df$names_clusters = factor(plot_df$names_clusters, 
                                levels = c("Cholangiocytes", "LSEC periportal", "LSEC pericentral", 
                                           "Endothelial cells (non-LSEC)", "Hepatocytes", "Kupffer cells",
                                           "Macrophages", "cDCs", "pDCs", "ab-T cells", "gd-T cells",
                                           "B cells", "Plasmablasts",
                                           "Stellate cells", "Dividing cells", "Doublets"))
plot_df = plot_df[plot_df$names_clusters!="Doublets",]

nmg = c("KRT7", "CD24",  "LILRA4", "IRF7",  "FCER1A", "CLEC10A",  "CCL23","CLEC1B",  "INMT","SELP",  
        "MARCO","CD5L",  "CYP2E1","ORM2",  "MS4A1","CD79A",  "CLEC14A","EDNRB",  "IGLC2","CD27",  
        "TRDC","KLRD1",  "TRAC","CD3E",  "DCN","COLEC11",  "S100A12","CD300E")
nmg = nmg[c(1,2,13,14,17,18,7,8,9,10,25,26,27,28,11,12,5,6,3,4,23,24,21,22,15,16,19,20)]

m1 = GetAssayData(hcells_css, slot="data")[nmg,rownames(plot_df)]
m_ct_fresh = apply(m1, 1, function(x) tapply(x, as.character(plot_df$names_clusters), mean))
m_ct_fresh[m_ct_fresh>4] = 4.01
m_ct_fresh[m_ct_fresh<(-4)] = -4.01

annot_df = unique(plot_df[,c(3,4)])
annot_df = data.frame(row.names = annot_df$names_clusters, "ct" = annot_df$names_major)
heat = pheatmap::pheatmap(scale(m_ct_fresh[c(4,7,10,9,5,14,11,8,3,12,1,6,2,13),]), 
                          clustering_method = "ward.D2", treeheight_row = 0,
                          treeheight_col = 20, fontsize_row = 8, fontsize_col = 8,
                          cluster_cols = F, cluster_rows = F,
                          annotation_row = annot_df, annotation_colors = list(ct = colsmajor[-6]),
                          color = colorRampPalette(rev(brewer.pal(n = 9, name = "RdBu")))(100))

pdf("figure_panels/fig1/heatmap_all_celltypes.pdf", height = 3.5, width = 7, useDingbats = F)
print(heat)
dev.off()

Figure 2

Main Figure

UMAP with cell types

allcells_css = readRDS(file = "data/processed/allcells_css_reannot.RDS")

load(file = "data/processed/healthy_srat_beforeFiltering.RData")
load(file = "data/processed/cond_srat_beforeFiltering.RData")
allcells_css = readRDS(file = "data/processed/allcells_css_reannot.RDS")

load(file = "data/processed/healthy_srat_beforeFiltering.RData")
load(file = "data/processed/cond_srat_beforeFiltering.RData")

UMAP with all cell types

plot_df = allcells_css@meta.data
plot_df = cbind(plot_df, allcells_css@reductions$umap_css@cell.embeddings)
plot_df$Condition = factor(plot_df$Condition, levels = c("healthy", "embolised", "regenerating"))
plot_df$allcells_simp[grepl("interaction", plot_df$allcells_simp)] = "Doublets"
plot_df$allcells_simp[grepl("Hepatocytes ", plot_df$allcells_simp)] = "Hepatocytes"
plot_df$allcells_simp = factor(plot_df$allcells_simp, 
                               levels = c("Cholangiocytes", "LSEC periportal", "LSEC pericentral", 
                                          "Endothelial cells (non-LSEC)", "Hepatocytes", "Kupffer cells",
                                          "Macrophages", "cDCs", "pDCs", "ab-T cells", "gd-T cells",
                                          "B cells", "Plasmablasts",
                                          "Stellate cells", "Dividing cells", "Doublets"))

pltumap = ggplot(plot_df, aes(y = UMAPCSS_2, x = UMAPCSS_1, colour = allcells_simp))+
  geom_point(size = pointsize)+
  labs(colour = "Cell Type")+
  scale_colour_manual(values = colsallct)+
  guides(colour = guide_legend(override.aes = list(size = 2)))+
  theme(aspect.ratio = 1,
        legend.title = element_text(hjust = 0),
        axis.line = element_blank(),
        axis.text = element_blank())

pdf("figure_panels/fig2/umap_all_celltypes.pdf", height = 5, width = 6, useDingbats = F)
print(pltumap)
dev.off()
png("figure_panels/fig2/umap_all_celltypes.png", height = 325, width = 400, antialias = "subpixel")
print(pltumap)
dev.off()

Proportion of each cell type per condition

df_cnt = table(plot_df$allcells_simp, plot_df$Condition)[-c(15,16),]
df_cnt_hep = reshape2::melt(apply(df_cnt, 2, function(x) round(x/sum(x)*100, 1))[5,])
df_cnt_nohep = reshape2::melt(apply(df_cnt[-5,], 2, function(x) round(x/sum(x)*100, 1)))

df_cnt_all = rbind(data.frame("Var1" = "Hepatocytes", "Var2" = rownames(df_cnt_hep), 
                              "value" = df_cnt_hep$value),
                   df_cnt_nohep)

mat_cnt_all = reshape2::dcast(data = df_cnt_all, formula = Var1 ~ Var2, value.var = "value")
rownames(mat_cnt_all) = mat_cnt_all$Var1
mat_cnt_all = mat_cnt_all[,-1]
ctord = hclust(dist(mat_cnt_all[,c(2,1,3)]))$order
ctord = c(7, 4, 10, 9, 5, 14, 11, 8, 3, 12,1,6,2,13)

annot_df = unique(plot_df[,c("major_ct","allcells_simp")])
annot_df = data.frame(row.names = annot_df$allcells_simp, "ct" = annot_df$major_ct)
heatp = pheatmap::pheatmap(mat_cnt_all[ctord,c(2,1,3)], cluster_cols = F, cluster_rows = F, 
                           treeheight_row = F, display_numbers = T, gaps_row = c(1,1), 
                           number_color = c("black", "white")[as.integer(mat_cnt_all[ctord,c(2,1,3)]>50)+1],
                           color = colorRampPalette(brewer.pal(n = 9, name = "Blues"))(100),
                           fontsize_row = 8, fontsize_col = 8,
                           annotation_row = annot_df, annotation_colors = list(ct = colsmajor[-6]))

pdf("figure_panels/fig2/heatmap_all_celltypes_prop.pdf", height = 3.5, width = 5, useDingbats = F)
print(heatp)
dev.off()

UMAP with conditions

randomrows = sample(1:nrow(plot_df), size = nrow(plot_df), replace = F)
pltumapcond = ggplot(plot_df[randomrows,], aes(y = UMAPCSS_2, x = UMAPCSS_1, colour = Condition))+
  geom_point(size = pointsize)+
  labs(colour = "Condition")+
  scale_colour_manual(values = colcond)+
  guides(colour = guide_legend(override.aes = list(size = 2)))+
  theme(aspect.ratio = 1,
        legend.title = element_text(hjust = 0),
        axis.line = element_blank(),
        axis.text = element_blank())

pdf("figure_panels/fig2/umap_condition.pdf", height = 5, width = 6, useDingbats = F)
print(pltumapcond)
dev.off()
png("figure_panels/fig2/umap_condition.png", height = 325, width = 400, antialias = "subpixel")
print(pltumapcond)
dev.off()

Top GO terms and load data

# loading and preparing data
go_enr_list = readRDS(file = "results/cond_effect/go_enr_list.RDS")

go_enr_major = go_enr_list$major_ct
for(cc in names(go_enr_major)){ # adding the terms for subsampled hepatocytes
  for(ct in names(go_enr_major[[cc]])){
    if(ct=="Hepatocytes"){
      go_enr_major[[cc]][[ct]] = go_enr_list$major_ct_hep[[cc]]$Hepatocytes
    }
    go_enr_major[[cc]][[ct]] = go_enr_major[[cc]][[ct]][go_enr_major[[cc]][[ct]]$DB=="GO Term",]
  }
}


for(comp in names(go_enr_major)){
  for(ct in names(go_enr_major[[comp]])){
    subdir = "figure_panels/fig2/goterms_cond_full/"
    go_enr_major[[comp]][[ct]]$geneID = unlist(go_enr_major[[comp]][[ct]]$geneID)
    write.table(go_enr_major[[comp]][[ct]], 
                file = paste0(subdir, "GOTermBP_", comp, "_", ct, ".csv"), 
                col.names = T, row.names = F, quote = F, sep = ",")
  }
}

Plotting GO Terms mixed between conditions

terms_list = list()
for(ct in unique(names(go_enr_major$healthy_v_embolised))){
  emb_terms = go_enr_major$healthy_v_embolised[[ct]][,c(2,7,8,11)]
  emb_terms = emb_terms[emb_terms$cond!="healthy",]
  reg_terms = go_enr_major$healthy_v_regenerating[[ct]][,c(2,7,8,11)]
  reg_terms = reg_terms[reg_terms$cond!="healthy",]
  both_terms = merge(emb_terms, reg_terms, by = 1, all = T)[,-c(4,7)]
  colnames(both_terms)[2:5] = c("qval_embolized", "genes_embolized", 
                                "qval_regenerating", "genes_regenerating")
  both_terms$qval_embolized[is.na(both_terms$qval_embolized)] = 1
  both_terms$qval_regenerating[is.na(both_terms$qval_regenerating)] = 1
  both_terms$genes_embolized[is.na(both_terms$genes_embolized)] = ""
  both_terms$genes_regenerating[is.na(both_terms$genes_regenerating)] = ""
  
  both_terms$genes_all = unlist(lapply(strsplit(paste0(both_terms$genes_embolized, "/",
                                                       both_terms$genes_regenerating),"/"), 
                                       function(x) paste0(unique(x[x!=""]), collapse = "/")))
  
  both_terms = both_terms[both_terms$qval_embolized<=0.05 | both_terms$qval_regenerating<=0.05,]
  
  both_terms_top = getTopTermsPaired(both_terms, ncl = 12, nt = 1)
  terms_list[[ct]] = both_terms_top
}

plt_list = list()
for(ct in names(terms_list)){
  sum_df = terms_list[[ct]][,c(1:3,7)]
  sum_df$Description = breakStr(as.character(sum_df$Description), n = 30)
  sum_df$qval_max[sum_df$qval_embolized>sum_df$qval_regenerating] = 1-sum_df$qval_max[sum_df$qval_embolized>sum_df$qval_regenerating]
  plot_df = reshape2::melt(sum_df[,1:3])
  plot_df$Description = factor(plot_df$Description, levels = sum_df$Description[order(sum_df$qval_max)])
  plot_df$variable = unlist(lapply(strsplit(as.character(plot_df$variable), "_"), function(x) x[2]))
  
  plt_list[[ct]] = ggplot(plot_df, aes(x = -log10(value), y = Description, fill = variable))+
    geom_col(position = "dodge")+
    geom_vline(xintercept = -log10(0.05), linetype = "dashed")+
    scale_x_continuous(limits = c(0, max(-log10(plot_df$value)+0.3)), expand = c(0,0))+
    scale_fill_manual(values = colcond)+
    theme(legend.position = "none",
          axis.ticks = element_line())
}

for(n in names(plt_list)){
  pdf(paste0("figure_panels/fig2/goterms_cond/goterms_mixedGO_", n, ".pdf"), 
      height = 2.8, width = 3)
  print(plt_list[[n]])
  dev.off()
}

cowplot::plot_grid(plotlist = plt_list, ncol = 4, align = "hv")

Top enriched GO Terms - group similar terms and report the top 1 of each of 5 groups detected

goplt = list()
gotab = list()
for(comp in names(go_enr_major)){
  for(gr in names(go_enr_major[[comp]])){
    conds = strsplit(comp, "_v_")[[1]]
    for(cc in conds){
      sub_df = go_enr_major[[comp]][[gr]][go_enr_major[[comp]][[gr]]$DB=="GO Term" &
                                            go_enr_major[[comp]][[gr]]$qvalue<=0.05 &
                                            go_enr_major[[comp]][[gr]]$cond==cc,]
      if(nrow(sub_df)>0){
        sub_df = getTopTerms(sub_df, ncl = 5, nt = 1)
        sub_df = sub_df[order(sub_df$qvalue, decreasing = F),]
        l = ifelse(nrow(sub_df)>10, 10, nrow(sub_df))
        sub_df = sub_df[1:l,]
        sub_df$geneID = unlist(sub_df$geneID)
        sub_df$Description = breakStr(as.character(sub_df$Description), 30)
        sub_df$Description = factor(sub_df$Description, 
                                    levels = rev(as.character(sub_df$Description)))
        
        goplt[[paste0(comp, "__", gr, "__", cc)]] = ggplot(sub_df, 
                                                           aes(x = -log10(qvalue), y = Description))+
          geom_col()+
          scale_x_continuous(expand = c(0,0), limits = c(0, max(-log10(sub_df$qvalue))+0.25))+
          labs(y = "GO Term Description", title = paste0(cc, " vs ", conds[conds!=cc]))+
          theme(axis.ticks.x = element_line(),
                axis.text.y = element_text(hjust = 1, vjust = 0.5, lineheight = 0.75,
                                           size = 7),
                plot.title = element_text(size = 10, hjust = 0),
                plot.title.position = "plot")
        gotab[[paste0(comp, "__", gr, "__", cc)]] = sub_df
      }
    }
  }
}
for(n in names(goplt)){
  pdf(paste0("figure_panels/fig2/goterms_cond/goterms_filtGO_", n, ".pdf"), 
      height = 2, width = 3)
  print(goplt[[n]])
  dev.off()
  
  write.csv(gotab[[n]], file = paste0("figure_panels/fig2/goterms_cond/goterms_filtGO_", n, ".csv"),
            row.names = F, quote = F)
}

DE between conditions for cell types

filt_comps = readRDS(file = "results/cond_effect/all_filt_cond_comps.RDS")

for(comp in names(filt_comps$major_ct)){
  subdir = "figure_panels/fig2/DE_tables/"
  de_df = filt_comps$major_ct[[comp]]
  de_df = de_df[de_df$celltype!="Hepatocytes",]
  de_df = rbind(de_df, filt_comps$major_ct_hep[[comp]])
  de_df = de_df[de_df$p_val_adj<=0.05,]
  
  write.csv(de_df[order(de_df$avg_logFC, decreasing = T),], 
            file = paste0(subdir, "DEcond_major_ct_", comp, ".csv"), 
            col.names = T, row.names = F, quote = F)
}

for(g in names(filt_comps)){
  for(comp in names(filt_comps[[g]])){
    subdir = file.path("to_send", g)
    write.csv(filt_comps[[g]][[comp]], file = paste0(subdir, "/DEconditions_", comp, "_", g, ".csv"), 
              col.names = T, row.names = F, quote = F)
  }
}

Major cell types

genes_to_plot = list("Hepatocytes" = c("HAMP", "SAA1", "FGA", "G0S2", "TNFRSF1A",
                                       "CYP3A7", "MT1A", "DDX21", "IL1RAP", "MT1X",
                                       "MGLL", "MFSD2A", "APOA4", "IRF7", "CEBPA"), 
                      "Immune" = c("S100A9", "CD81", "FCGR1A", "GBP5", "RUNX3", 
                                   "CD300E", "MNDA", "IL18BP", "IL4I1", "WDFY4",
                                   "TRDC", "TRBC1", "IFNG", "CD160", "IFITM1"), 
                      "Cholangiocytes" = c("CCL2", "IRF1", "KRT19", "CCL20", "ICAM1",
                                           "MAP3K12", "EPSTI1", "P4HA1", "PEAK1", "SEC24A",
                                           "LCN2", "RAMP1", "ITGB4", "BIK", "CCL28"), 
                      "Mesenchymal" = c(), 
                      "Endothelial" = c("SOX18", "PLCG2", "TFPI2", "KLF2", "STC1",
                                        "CXXC5", "NPR3", "CDK6", "ADGRG6", "PDGFB",
                                        "RFPL1", "ITGB3", "ADAMTS4", "KLF13", "GPR182"))

plt_list_cond = list()
df_list_cond = list()
for(ct in unique(filt_comps$major_ct$healthy_v_embolised$celltype)){
  g = if(ct=="Hepatocytes") "major_ct_hep" else "major_ct" #use correct Hep DE
  
  # prepare data frame
  plt_reg = filt_comps[[g]]$healthy_v_regenerating[,c(1,3,4,5)]
  plt_reg = unique(plt_reg[plt_reg$celltype==ct,])
  plt_emb = filt_comps[[g]]$healthy_v_embolised[,c(1,3,4,5)]
  plt_emb = unique(plt_emb[plt_emb$celltype==ct,])
  rownames(plt_reg) = plt_reg$gene
  rownames(plt_emb) = plt_emb$gene
  
  # add FC/pval for genes that are not in common
  plt_df = merge(plt_emb, plt_reg, by = 0, all = T)
  rownames(plt_df) = plt_df[,1]
  plt_df = plt_df[,-c(1,3,6,7)]
  colnames(plt_df) = c("gene", "FC_emb", "pval_emb", "FC_reg", "pval_reg")
  plt_df$gene = rownames(plt_df)
  plt_df$FC_emb[is.na(plt_df$FC_emb)] = 0
  plt_df$FC_reg[is.na(plt_df$FC_reg)] = 0
  plt_df$pval_emb[is.na(plt_df$pval_emb)] = 1
  plt_df$pval_reg[is.na(plt_df$pval_reg)] = 1
  
  # condition labels
  plt_df$cond = ifelse(plt_df$FC_emb<=(-0.2) & plt_df$pval_emb<=0.05 & plt_df$FC_reg>=0, "embolised",
                       ifelse(plt_df$FC_reg<=(-0.2) & plt_df$pval_reg<=0.05 & plt_df$FC_emb>=0,
                              "regenerating",
                              ifelse(plt_df$FC_reg<=(-0.2) & plt_df$pval_reg<=0.05 & 
                                       plt_df$FC_emb<=(-0.2) & plt_df$pval_emb<=0.05, "both","other")))
  plt_df$cond = factor(plt_df$cond, levels = c("both", "embolised", "regenerating", "other"))
  plt_df = plt_df[order(plt_df$cond, decreasing = T),]
  
  # genes to plot
  b_g_plt = genes_to_plot[[ct]][1:5]
  emb_g_plt = genes_to_plot[[ct]][6:10]
  reg_g_plt = genes_to_plot[[ct]][11:15]
  
  cols = c("both" = "#C54635", "regenerating" = "salmon", "embolised" = "darkred", "other" = "grey85")
  plt = ggplot(plt_df, aes(x = FC_emb, y = FC_reg, colour = cond))+
    geom_vline(xintercept = 0)+
    geom_hline(yintercept = 0)+
    geom_point()+
    geom_label_repel(data = plt_df[plt_df$gene %in% c(emb_g_plt, reg_g_plt, b_g_plt),], 
                     mapping = aes(label = gene), show.legend = F, min.segment.length = 0, 
                     size = 2.75, label.padding = 0.15)+
    scale_colour_manual(values = cols)+
    labs(title = ct, x = "logFC(healthy vs embolised)", colour = "Condition",
         y = "logFC(healthy vs regenerating)")+
    theme_bw()+
    theme(axis.text = element_text(colour = "black"),
          aspect.ratio = 1)
  
  plt_list_cond[[ct]] = plt
}

pdf("figure_panels/fig2/DE_cond_major_celltypes.pdf", height = 5, width = 6, useDingbats = F)
print(plt_list_cond)
dev.off()
pdf("figure_panels/fig2/DE_cond_major_celltypes_noLeg.pdf", height = 5, width = 6, useDingbats = F)
plt_list_cond = lapply(plt_list_cond, function(x) x+theme(legend.position = "none"))
print(plt_list_cond)
dev.off()

All cell types

plt_list_cond = list()
df_list_cond = list()
for(ct in unique(filt_comps$cell_type$healthy_v_embolised$celltype)){
  g = if(ct=="Hepatocytes") "cell_type_hep" else "cell_type" #use correct Hep DE
  
  # prepare data frame
  plt_reg = filt_comps[[g]]$healthy_v_regenerating[,c(1,3,4,5)]
  plt_reg = unique(plt_reg[plt_reg$celltype==ct,])
  plt_emb = filt_comps[[g]]$healthy_v_embolised[,c(1,3,4,5)]
  plt_emb = unique(plt_emb[plt_emb$celltype==ct,])
  rownames(plt_reg) = plt_reg$gene
  rownames(plt_emb) = plt_emb$gene
  
  # add FC/pval for genes that are not in common
  plt_df = merge(plt_emb, plt_reg, by = 0, all = T)
  rownames(plt_df) = plt_df[,1]
  plt_df = plt_df[,-c(1,3,6,7)]
  colnames(plt_df) = c("gene", "FC_emb", "pval_emb", "FC_reg", "pval_reg")
  plt_df$gene = rownames(plt_df)
  plt_df$FC_emb[is.na(plt_df$FC_emb)] = 0
  plt_df$FC_reg[is.na(plt_df$FC_reg)] = 0
  plt_df$pval_emb[is.na(plt_df$pval_emb)] = 1
  plt_df$pval_reg[is.na(plt_df$pval_reg)] = 1
  
  # condition labels
  plt_df$cond = ifelse(plt_df$FC_emb<=(-0.2) & plt_df$pval_emb<=0.05 & plt_df$FC_reg>=0, "embolised",
                       ifelse(plt_df$FC_reg<=(-0.2) & plt_df$pval_reg<=0.05 & plt_df$FC_emb>=0,
                              "regenerating",
                              ifelse(plt_df$FC_reg<=(-0.2) & plt_df$pval_reg<=0.05 & 
                                       plt_df$FC_emb<=(-0.2) & plt_df$pval_emb<=0.05, "both","other")))
  plt_df$cond = factor(plt_df$cond, levels = c("both", "embolised", "regenerating", "other"))
  plt_df = plt_df[order(plt_df$cond, decreasing = T),]
  
  # genes to plot
  ord = order(plt_df$FC_emb+plt_df$FC_reg, decreasing = F)
  b_g_plt = plt_df$gene[ord][plt_df$cond[ord]=="both" & plt_df$pval_emb[ord]<=0.05 & plt_df$pval_reg[ord]<=0.05][1:5]
  ord = order(plt_df$FC_emb, decreasing = F)
  emb_g_plt = plt_df$gene[ord][plt_df$cond[ord]=="embolised" & plt_df$pval_emb[ord]<=0.05][1:5]
  ord = order(plt_df$FC_reg, decreasing = F)
  reg_g_plt = plt_df$gene[ord][plt_df$cond[ord]=="regenerating" & plt_df$pval_reg[ord]<=0.05][1:5]
  
  cols = c("both" = "#C54635", "regenerating" = "salmon", "embolised" = "darkred", "other" = "grey85")
  plt = ggplot(plt_df, aes(x = FC_emb, y = FC_reg, colour = cond))+
    geom_vline(xintercept = 0)+
    geom_hline(yintercept = 0)+
    geom_point()+
    geom_label_repel(data = plt_df[plt_df$gene %in% c(emb_g_plt, reg_g_plt, b_g_plt),], 
                     mapping = aes(label = gene), show.legend = F, min.segment.length = 0, 
                     size = 2.75, label.padding = 0.15)+
    scale_colour_manual(values = cols)+
    labs(title = ct, x = "logFC(healthy vs embolised)", colour = "Condition",
         y = "logFC(healthy vs regenerating)")+
    theme_bw()+
    theme(axis.text = element_text(colour = "black"),
          aspect.ratio = 1)
  
  plt_list_cond[[ct]] = plt
}

pdf("figure_panels/fig2/DE_cond_all_celltypes.pdf", height = 5, width = 6, useDingbats = F)
print(plt_list_cond)
dev.off()
pdf("figure_panels/fig2/DE_cond_all_celltypes_noLeg.pdf", height = 5, width = 6, useDingbats = F)
plt_list_cond = lapply(plt_list_cond, function(x) x+theme(legend.position = "none"))
print(plt_list_cond)
dev.off()

Count DE genes per cell type in conditions - major cell types

de_df = filt_comps$major_ct$healthy_v_embolised
de_df = de_df[de_df$p_val_adj<=0.05 & abs(de_df$avg_logFC)>=0.2,]
genes_up = tapply(de_df$gene[de_df$avg_logFC>0], de_df$celltype[de_df$avg_logFC>0], list)
genes_dn = tapply(de_df$gene[de_df$avg_logFC<0], de_df$celltype[de_df$avg_logFC<0], list)
de_hep = filt_comps$major_ct_hep$healthy_v_embolised
genes_up$Hepatocytes = de_hep$gene[de_hep$avg_logFC>=0.2 & de_hep$p_val_adj<=0.05]
genes_dn$Hepatocytes = de_hep$gene[de_hep$avg_logFC<=(-0.2) & de_hep$p_val_adj<=0.05]
de_df_g = rbind(reshape2::melt(genes_up), reshape2::melt(genes_dn))
de_df_g$dedir = c(rep("higher in healthy", length(unlist(genes_up))), 
                  rep("higher in embolised", length(unlist(genes_dn))))

de_df_r = filt_comps$major_ct$healthy_v_regenerating
de_df_r = de_df_r[de_df_r$p_val_adj<=0.05 & abs(de_df_r$avg_logFC)>=0.2,]
genes_up = tapply(de_df_r$gene[de_df_r$avg_logFC>0], de_df_r$celltype[de_df_r$avg_logFC>0], list)
genes_dn = tapply(de_df_r$gene[de_df_r$avg_logFC<0], de_df_r$celltype[de_df_r$avg_logFC<0], list)
de_hep = filt_comps$major_ct_hep$healthy_v_regenerating
genes_up$Hepatocytes = de_hep$gene[de_hep$avg_logFC>=0.2 & de_hep$p_val_adj<=0.05]
genes_dn$Hepatocytes = de_hep$gene[de_hep$avg_logFC<=(-0.2) & de_hep$p_val_adj<=0.05]
de_df_r_g = rbind(reshape2::melt(genes_up), reshape2::melt(genes_dn))
de_df_r_g$dedir = c(rep("higher in healthy", length(unlist(genes_up))), 
                    rep("higher in regenerating", length(unlist(genes_dn))))


counts_de = rbind(data.frame(table(de_df_g$L1, de_df_g$dedir)), data.frame(table(de_df_r_g$L1, de_df_r_g$dedir)))
counts_de$comp = rep(c("healthy vs embolised", "healthy vs regenerating"), each = 10)
counts_de$Var2 = factor(counts_de$Var2, 
                        levels = c("higher in healthy", "higher in embolised", "higher in regenerating"))

plt = ggplot(counts_de, aes(x = Var1, y = Freq, fill = Var2))+
  facet_wrap(~comp, nrow = 2)+
  scale_fill_manual(values = c("higher in healthy" = "orange", "higher in regenerating" = "salmon", 
                               "higher in embolised" = "darkred"))+
  scale_y_continuous(expand = c(0,0), limits = c(0, 4000))+
  labs(fill = "DE genes", x = "Cell types", y = "# DE genes")+
  geom_bar(stat = "identity")+
  theme_classic()+
  theme(legend.justification=c(0,1), legend.position=c(0,1),
        legend.box.background = element_rect(colour = "transparent", fill = "transparent"),
        legend.background = element_rect(colour = "transparent", fill = "transparent"),
        legend.key.size = unit(0.4, "cm"),
        axis.text = element_text(colour = "black"),
        axis.text.x = element_text(angle = 45, hjust = 1, vjust = 1))

pdf("figure_panels/fig2/barplot_decond_major.pdf", height = 5, width = 3, useDingbats = F)
print(plt)
dev.off()
png("figure_panels/fig2/barplot_decond_major.png", height = 500, width = 350, antialias = "subpixel")
print(plt)
dev.off()

Count DE genes per cell type in conditions - all cell types

de_df = filt_comps$cell_type_simp$healthy_v_embolised
de_df = de_df[de_df$p_val_adj<=0.05 & abs(de_df$avg_logFC)>=0.2,]
genes_up = tapply(de_df$gene[de_df$avg_logFC>0], de_df$celltype[de_df$avg_logFC>0], list)
genes_dn = tapply(de_df$gene[de_df$avg_logFC<0], de_df$celltype[de_df$avg_logFC<0], list)
de_hep = filt_comps$major_ct_hep$healthy_v_embolised
genes_up$Hepatocytes = de_hep$gene[de_hep$avg_logFC>=0.2 & de_hep$p_val_adj<=0.05]
genes_dn$Hepatocytes = de_hep$gene[de_hep$avg_logFC<=(-0.2) & de_hep$p_val_adj<=0.05]
de_df_g = rbind(reshape2::melt(genes_up), reshape2::melt(genes_dn))
de_df_g$dedir = c(rep("higher in healthy", length(unlist(genes_up))), 
                  rep("higher in embolised", length(unlist(genes_dn))))

de_df_r = filt_comps$cell_type_simp$healthy_v_regenerating
de_df_r = de_df_r[de_df_r$p_val_adj<=0.05 & abs(de_df_r$avg_logFC)>=0.2,]
genes_up = tapply(de_df_r$gene[de_df_r$avg_logFC>0], de_df_r$celltype[de_df_r$avg_logFC>0], list)
genes_dn = tapply(de_df_r$gene[de_df_r$avg_logFC<0], de_df_r$celltype[de_df_r$avg_logFC<0], list)
de_hep = filt_comps$major_ct_hep$healthy_v_regenerating
genes_up$Hepatocytes = de_hep$gene[de_hep$avg_logFC>=0.2 & de_hep$p_val_adj<=0.05]
genes_dn$Hepatocytes = de_hep$gene[de_hep$avg_logFC<=(-0.2) & de_hep$p_val_adj<=0.05]
de_df_r_g = rbind(reshape2::melt(genes_up), reshape2::melt(genes_dn))
de_df_r_g$dedir = c(rep("higher in healthy", length(unlist(genes_up))), 
                    rep("higher in regenerating", length(unlist(genes_dn))))

counts_de = rbind(data.frame(table(de_df_g$L1, de_df_g$dedir)), 
                  data.frame(table(de_df_r_g$L1, de_df_r_g$dedir)))
counts_de$comp = rep(c("healthy vs embolised", "healthy vs regenerating"), each = 14)
counts_de$Var2 = factor(counts_de$Var2, 
                        levels = c("higher in healthy", "higher in embolised", "higher in regenerating"))

plt = ggplot(counts_de, aes(x = Var1, y = Freq, fill = Var2))+
  facet_wrap(~comp)+
  scale_fill_manual(values = c("higher in healthy" = "orange", 
                               "higher in regenerating" = "salmon", "higher in embolised" = "darkred"))+
  scale_y_continuous(expand = c(0,0), limits = c(0, 3500))+
  labs(fill = "DE genes", x = "Cell types", y = "# DE genes")+
  geom_bar(stat = "identity")+
  theme_classic()+
  theme(legend.justification=c(0,1), legend.position=c(0,1),
        legend.box.background = element_rect(colour = "transparent", fill = "transparent"),
        legend.background = element_rect(colour = "transparent", fill = "transparent"),
        legend.key.size = unit(0.4, "cm"),
        axis.text = element_text(colour = "black"),
        axis.text.x = element_text(angle = 45, hjust = 1, vjust = 1))

pdf("figure_panels/fig2/barplot_decond_all.pdf", height = 4, width = 6, useDingbats = F)
print(plt)
dev.off()
png("figure_panels/fig2/barplot_decond_all.png", height = 350, width = 500, antialias = "subpixel")
print(plt)
dev.off()

Supplementary

Gene and UMI counts per major cell type and condition

plot_df = allcells_css@meta.data
plot_df$Condition = factor(plot_df$Condition, levels = c("healthy", "embolised", "regenerating"))
plot_df$major_ct = factor(plot_df$major_ct, levels = c("Hepatocytes", "Endothelial", "Cholangiocytes", "Immune", "Mesenchymal"))

vio_counts_ct = ggplot(plot_df[!is.na(plot_df$major_ct),], 
                       aes(y = nCount_SCT, x = Condition, fill = Condition))+
  facet_wrap(~major_ct, scales = "free_x")+
  geom_violin()+
  scale_y_log10(name = "# UMI (normalised)")+
  scale_fill_manual(values = colcond)+
  theme(panel.grid.major.y = element_line(colour = "grey85"),
        legend.position = "none",
        axis.text = element_text(),
        axis.text.x = element_text(size = 9),
        axis.title.x = element_text(size = 10),
        strip.text = element_text(size = 9),
        strip.background = element_rect(fill = "transparent", colour = "black", size = 0.9))

pdf("figure_panels/fig2/violin_ncounts_major_celltype.pdf", height = 4, width = 7, useDingbats = F)
print(vio_counts_ct)
dev.off()
png("figure_panels/fig2/violin_ncounts_major_celltype.png", height = 425, width = 550, antialias = "subpixel")
print(vio_counts_ct)
dev.off()

vio_counts_ct = ggplot(plot_df[!is.na(plot_df$major_ct),], 
                       aes(y = nFeature_SCT, x = Condition, fill = Condition))+
  facet_wrap(~major_ct, scales = "free_x")+
  geom_violin()+
  scale_y_log10(name = "# Genes")+
  scale_fill_manual(values = colcond)+
  theme(panel.grid.major.y = element_line(colour = "grey85"),
        legend.position = "none",
        axis.text = element_text(),
        axis.text.x = element_text(size = 9),
        axis.title.x = element_text(size = 10),
        strip.text = element_text(size = 9),
        strip.background = element_rect(fill = "transparent", colour = "black", size = 0.9))

pdf("figure_panels/fig2/violin_ngenes_major_celltype.pdf", height = 4, width = 7, useDingbats = F)
print(vio_counts_ct)
dev.off()
png("figure_panels/fig2/violin_ngenes_major_celltype.png", height = 425, width = 550, antialias = "subpixel")
print(vio_counts_ct)
dev.off()

nUMI in filtered and kept cells

c_meta = Reduce(rbind, lapply(cond_srat, function(x) x@meta.data))[,c(11,12,13,14,15,17,23)]
h_meta = Reduce(rbind, lapply(healthy_srat, function(x) x@meta.data))[,c(11,12,13,14,15,17,23)]
all_meta = rbind(h_meta, c_meta)

all_meta$keep_allfilt = factor(c("No", "Yes")[all_meta$keep_allfilt+1], levels = c("Yes", "No"))
all_meta$Name = factor(all_meta$Name, 
                       levels = paste0("sc_", c(paste0("H",1:3),paste0("E",c(1:3,5:7)),paste0("R",c(1:3,5:7)))))
levels(all_meta$Name) = paste0("sc_", c(paste0("H",1:3),paste0("E",1:6),paste0("R",1:6)))

n_cells = all_meta %>% count(Name, Fraction, keep_allfilt)

plt = ggplot(all_meta, aes(x = Fraction, y = nCount_SCT, fill = keep_allfilt, colour = keep_allfilt))+
  facet_wrap(~Name, scales = "free", nrow = 3)+
  geom_violin(scale = "width")+
  scale_colour_manual(values = c("Yes" = "grey20","No" = "grey80"))+
  scale_fill_manual(values = c("Yes" = "grey20","No" = "grey80"))+
  scale_y_log10()+
  labs(y = "nUMI", colour = "keep", fill = "keep")+
  theme(strip.background = element_rect(fill = "transparent", colour = "black", size = 1),
        strip.text = element_text(margin = margin(2,0,2,0), size = 9),
        axis.ticks = element_line(), 
        axis.text.y = element_text(size = 6.5))

pdf("figure_panels/fig2/filtering_nUMI.pdf", height = 3.3, width = 7.1, useDingbats = F)
print(plt)
dev.off()

UMAP with healthy donors split

plot_df = data.frame(allcells_css@reductions$umap_css@cell.embeddings)
plot_df$Donor = factor(allcells_css@meta.data$Name)
plot_df$Donor = plyr::revalue(plot_df$Donor, c("sc_E5" = "sc_E4", "sc_R5" = "sc_R4", 
                                               "sc_E6" = "sc_E5", "sc_R6" = "sc_R5",
                                               "sc_E7" = "sc_E6", "sc_R7" = "sc_R6"))
plot_df$Donor = factor(plot_df$Donor, levels = c("sc_H1", "sc_H2", "sc_H3", "sc_E1", "sc_R1", "sc_E2", 
                                                 "sc_R2", "sc_E3", "sc_R3", "sc_E4", "sc_R4", "sc_E5", 
                                                 "sc_R5", "sc_E6", "sc_R6"))
plot_df$Condition = factor(allcells_css@meta.data$Condition, 
                           levels = c("healthy", "embolised", "regenerating"))
plot_df$major_ct = allcells_css@meta.data$major_ct
plot_df$allcells_major = allcells_css@meta.data$allcells_major
plot_df$major_ct[is.na(plot_df$major_ct)] = plot_df$allcells_major[is.na(plot_df$major_ct)]
plot_df$major_ct[plot_df$major_ct=="Dividing cells"] = "Immune" # the detected dividing cells are mostly (if not all) immune 
plot_df$major_ct = factor(plot_df$major_ct, levels = c("Hepatocytes", "Endothelial","Immune",
                                                       "Cholangiocytes","Mesenchymal", "Doublets"))

plt = ggplot(plot_df[sample(1:nrow(plot_df), nrow(plot_df), replace = F),], 
             aes(x = UMAPCSS_1, y = UMAPCSS_2, colour = major_ct))+
  facet_wrap(~Donor, drop = T, nrow = 3, ncol = 5)+
  geom_point(size = 0.08)+
  guides(colour = guide_legend(override.aes = list(size = 3), title = "Donors"))+
  scale_colour_manual(values = colsmajor)+
  theme_classic()+
  th_gen+
  theme(axis.line = element_blank(),
        axis.ticks = element_blank(),
        axis.title = element_blank(),
        axis.text = element_blank(),
        strip.text.x = element_text(size = 8, margin = margin(0.06,0,0.06,0, "cm")),
        strip.background.x = element_rect(size = 0.5, colour = "transparent"),
        legend.title = element_text(hjust = 0),
        aspect.ratio = 1)

pdf("figure_panels/fig2/umapAll_fresh_donors_split.pdf", 
    useDingbats = F, height = 4.1, width = 6.4)
print(plt)
dev.off()
png("figure_panels/fig2/umapAll_fresh_donors_split.png", 
    height=8, width=15, unit="cm", res=600, antialias = "subpixel")
print(plt)
dev.off()
pdf("figure_panels/fig2/umapAll_fresh_donors_noLeg_split.pdf", 
    useDingbats = F, height = 4.1, width = 5.8)
print(plt+theme(legend.position = "none"))
dev.off()
png("figure_panels/fig2/umapAll_fresh_donors_noLeg_split.png", 
    height=8, width=11, unit="cm", res=600, antialias = "subpixel")
print(plt+theme(legend.position = "none"))
dev.off()
pdf("figure_panels/fig2/umapAll_fresh_donors_split_cond.pdf", 
    useDingbats = F, height = 4.1, width = 6.4)
print(plt+facet_wrap(Condition~Donor, drop = T, nrow = 3, ncol = 5))
dev.off()
png("figure_panels/fig2/umapAll_fresh_donors_split_cond.png", 
    height=8, width=15, unit="cm", res=600, antialias = "subpixel")
print(plt+facet_wrap(Condition~Donor, drop = T, nrow = 3, ncol = 5))
dev.off()

Figure 3

Main Figure

Zonation between conditions

# gene expression
hep_cells = readRDS(file = "results/zonation_cond/hep_cells_zonation_rank.RDS")

# fitted expression
hep_sig_fits = readRDS(file = "results/zonation_cond/hep_sig_fits.RDS")
hep_fits_qval = readRDS(file = "results/zonation_cond/hep_fits_qval.RDS")

# GO and clusters
hep_res_list = readRDS(file = "results/zonation_cond/hep_got_clustering_list.RDS")

g_list = c( # embolised clusters
  "COX7C", # oxygen transport chain (also in regen 2)
  "CYP39A1", # steroid metabolism
  "ARG1", # organic acid catabolic process (also in regen 2)
  "PROX1", # developing liver marker
  "COPA", # vesicle trafficking (also in regen 1)
  "CDH2", # cluster 4
  "CD151", # cluster 4
           # regenerating clusters
  "AGPAT2", # lipid metabolism
  "COX6C", # electron transport chain
  "PTGR1", # fatty acid metabolism
  "FOXA3", # liver development (cluster 1)
  "FOXO1", # control of metabolism and CC arrest
  "CYP2A6", # cluster 4
  "CYP2B6", # cluster 4
  "CYP4A11", # cluster 4
  "SDC4", # cluster 4
  "STAT1", # cluster 4
  # normal zonation
  "SAA1", "SAA2", "HAMP", "C3", "CYP2E1","CYP1A2","HULC","BCHE","CYP3A4",
  "CRP", "SDS", "HAL", "IGFBP1", "IGFBP2", "BAAT", "SLCO1B3")
hep_df = data.frame(vals = c(hep_cells$healthy$zonation_pt, hep_cells$embolised$zonation_pt,
                              hep_cells$regenerating$zonation_pt), 
                     Condition = c(rep("healthy", length(hep_cells$healthy$zonation_pt)), 
                                   rep("embolised", length(hep_cells$embolised$zonation_pt)), 
                                   rep("regenerating", length(hep_cells$regenerating$zonation_pt))),
                     Donor = c(hep_cells$healthy$Donor, 
                               hep_cells$embolised$Donor, hep_cells$regenerating$Donor),
                     ct = c(hep_cells$healthy$allcells_simp, 
                               hep_cells$embolised$allcells_simp, hep_cells$regenerating$allcells_simp))
hep_df$bins10 = cut(hep_df$vals, 10)
hep_df$Condition = factor(hep_df$Condition, levels = c("healthy", "embolised", "regenerating"))
levels(hep_df$Donor) = c("sc_E1/R1", "sc_E2/R2", "sc_E3/R3", "sc_E4/R4", "sc_E5/R5", "sc_E6/R6", 
                         "sc_H1", "sc_H2", "sc_H3")

plt_dists = ggplot(hep_df, aes(x = bins10, fill = Condition))+
     facet_wrap(~Condition)+
     geom_bar()+
     labs(x = "zonation (binned)", y = "Number of cells")+
     scale_y_continuous(expand = c(0,0))+
     scale_fill_manual(values = colcond)+
     coord_flip()+
     guides(fill = guide_legend(title.position = "left"))+
     theme(axis.text.y = element_blank(),
           legend.title.align = 0,
           legend.position = "bottom",
           legend.box.margin = margin(0,0,0,0),
           legend.box.spacing = unit(0.05, "cm"))

pdf("figure_panels/fig3/hep_zonation_conditionDist.pdf", height = 2.3, width = 3.6, useDingbats = F)
print(plt_dists)
dev.off()

Donor density per condition

hep_don = ggplot(hep_df, aes(x = vals, colour = Donor))+
     facet_wrap(~Condition, scales = "free_y")+
     geom_hline(yintercept = 0)+
     geom_density()+
     labs(x = "zonation", y = "cell density")+
     scale_y_continuous(expand = c(0,0))+
     coord_flip()+
     guides(colour = guide_legend(title.position = "left", nrow = 3))+
     theme(axis.text.y = element_blank(),
           axis.ticks.x = element_line(),
           strip.text = element_text(margin = margin(0.04,0,0.04,0, "cm"), size = 7.5),
           legend.title.align = 0,
           legend.position = "bottom",
           legend.box.margin = margin(0,0,0,0),
           legend.box.spacing = unit(0.05, "cm"))

pdf("figure_panels/fig3/hep_zonation_conditionDonors.pdf", height = 3, width = 3.6, useDingbats = F)
print(hep_don)
dev.off()

Zonation grouped by donors

hep_don = ggplot(hep_df, aes(x = vals, colour = Condition))+
     facet_wrap(~Donor, scales = "free_y")+
     geom_hline(yintercept = 0)+
     geom_density()+
     labs(x = "zonation", y = "cell density")+
     scale_colour_manual(values = colcond)+
     scale_y_continuous(expand = c(0,0))+
     coord_flip()+
     guides(colour = guide_legend(title.position = "left", ncol = 3))+
     theme(axis.text.y = element_blank(),
           axis.ticks.x = element_line(),
           strip.text = element_text(margin = margin(0.04,0,0.04,0, "cm"), size = 7.5),
           legend.title.align = 0,
           legend.position = "bottom",
           legend.box.margin = margin(0,0,0,0),
           legend.box.spacing = unit(0.05, "cm"))

pdf("figure_panels/fig3/hep_zonation_DonorsCond.pdf", height = 3, width = 3.6, useDingbats = F)
print(hep_don)
dev.off()

Hep binned zonation normalised to healthy

hep_df = data.frame(vals = c(hep_cells$healthy$zonation_pt, hep_cells$embolised$zonation_pt,
                              hep_cells$regenerating$zonation_pt), 
                     Condition = c(rep("healthy", length(hep_cells$healthy$zonation_pt)), 
                                   rep("embolised", length(hep_cells$embolised$zonation_pt)), 
                                   rep("regenerating", length(hep_cells$regenerating$zonation_pt))))
hep_df$bins10 = cut(hep_df$vals, 10)
hep_df$Condition = factor(hep_df$Condition, levels = c("healthy", "embolised", "regenerating"))
hep_df = data.frame(table(hep_df$Condition, hep_df$bins10))
hep_df = hep_df[order(hep_df$Var1),]
hep_df$Freqnorm = unlist(tapply(hep_df$Freq, hep_df$Var1, function(x) x/sum(x)))
hep_df$Freqnorm_h = hep_df$Freqnorm/mean(hep_df$Freqnorm[hep_df$Var1=="healthy"])

plt_dists = ggplot(hep_df, aes(x = Var2, fill = Var1, y = Freqnorm_h))+
     facet_wrap(~Var1)+
     geom_col()+
     labs(x = "zonation (binned)", y = "Proportion of cells (compared to healthy)")+
     scale_y_continuous(expand = c(0,0), labels = c("0", "0.5", "1", "1.5", "2", "2.5"))+
     scale_fill_manual(values = colcond)+
     coord_flip()+
     guides(fill = guide_legend(title.position = "left"))+
     theme(axis.text.y = element_blank(),
           axis.text.x = element_text(size = 6),
           legend.position = "none")

pdf("figure_panels/fig3/hep_zonation_conditionDist_norm.pdf", 
    height = 2, width = 3.8, useDingbats = F)
print(plt_dists)
dev.off()

Plot GO Terms (general)

go_theme = theme_bw()+
  theme(axis.text = element_text(colour = "black", size = 7.5),
        axis.title = element_text(size = 8),
        plot.title = element_text(size = 9),
        plot.title.position = "plot",
        plot.subtitle = element_text(size = 7.5),
        axis.text.y = element_text(vjust = 0.6, colour = c("grey45", "grey17")),
        panel.grid.major.y = element_blank())

gopltFunc = function(plot_df, tit = "", subtit = ""){
  plot_df$Description = breakStr(plot_df$Description, 30)
  plot_df$Description = factor(plot_df$Description, levels = rev(plot_df$Description))
  plot_df$fill = as.character(rep(1:2, ceiling(nrow(plot_df)/2)))[1:nrow(plot_df)]
  plt = ggplot(plot_df, aes(x = -log10(qvalue), y = Description, fill = fill))+
    geom_col(show.legend = F)+
    scale_x_continuous(expand = c(0,0), lim = c(0, max(-log10(plot_df$qvalue))+1))+
    scale_fill_manual(values = c("grey17", "grey45"))+
    labs(title = tit, subtitle = subtit)+
    go_theme
  return(plt)
}

pdf("figure_panels/fig3/hep_go_emb_notcorr.pdf", height = 3.2, width = 3.6, useDingbats = F)
print(gopltFunc(hep_res_list$embolised$go_cl$all, tit = "GO Terms - Embolised", subtit = "cor < 0.3"))
dev.off()

pdf("figure_panels/fig3/hep_go_emb_corr.pdf", height = 3.2, width = 3.6, useDingbats = F)
print(gopltFunc(hep_res_list$embolised$go_cl$pos, tit = "GO Terms - Embolised", subtit = "cor < 0.3"))
dev.off()

pdf("figure_panels/fig3/hep_go_reg_notcorr.pdf", height = 3.2, width = 3.6, useDingbats = F)
print(gopltFunc(hep_res_list$regenerating$go_cl$all, tit = "GO Terms - Regenerating", subtit = "cor >= 0.3"))
dev.off()

pdf("figure_panels/fig3/hep_go_reg_corr.pdf", height = 3.2, width = 3.6, useDingbats = F)
print(gopltFunc(hep_res_list$regenerating$go_cl$pos, tit = "GO Terms - Regenerating", subtit = "cor >= 0.3"))
dev.off()

Plot GO Terms (each cluster)

pathgo = "figure_panels/fig3/goterms_clusters/"
dir.create(pathgo, showWarnings = FALSE)

for(cc in names(hep_res_list)){
  tit = ifelse(cc=="embolised", "GO Terms - Embolised", "GO Terms - Regenerating")
  for(n in 1:5){
    plot_df = hep_res_list[[cc]]$go_cl[[as.character(n)]]
    if(nrow(plot_df)>0){
      plt = gopltFunc(plot_df, tit = tit, subtit = paste0("Cluster ", n, "; cor < 0.3"))
      if(nrow(plot_df)%%2==1){
        plt = plt + theme(axis.text.y = element_text(vjust = 0.6, colour = c("grey17","grey45")))
      }
      pdf(paste0(pathgo, "hep_go_", cc, "_cl", n, ".pdf"), height = 3.2, width = 3.6, useDingbats = F)
      print(plt)
      dev.off()
    }
  }
}

Plots for individual genes

geneplot_theme = theme_bw()+
    theme(aspect.ratio = 1/1.5,
          panel.grid = element_blank(),
          axis.text = element_text(colour = "black", size = 7),
          axis.title = element_text(size = 8),
          plot.title = element_text(size = 10, face = "italic"),
          plot.title.position = "plot",
          legend.position = "bottom",
          legend.box.margin = margin(0,0,0,0),
          legend.box.spacing = unit(0.01,"cm"),
          legend.text = element_text(size = 8),
          legend.title = element_text(size = 9))

plt_gene_list = list()
for(g in g_list){
  plt_df = data.frame("exp" = c(hep_sig_fits$healthy[,g], hep_sig_fits$embolised[,g]),
                    "cond" = rep(c("healthy", "embolised"), each = 100),
                    "t" = rep(1:100, 2))
  plt_df$cond = factor(plt_df$cond, levels = c("healthy", "embolised"))
  pltemb = ggplot(plt_df, aes(x = t, y = exp, group = cond, col = cond))+
    geom_line(size = 1.5)+
    labs(x = "zonation", y = "Expression", title = g)+
    scale_colour_manual(values = colcond)+
    geneplot_theme
  
  plt_df = data.frame("exp" = c(hep_sig_fits$healthy[,g], hep_sig_fits$regenerating[,g]),
                    "cond" = rep(c("healthy", "regenerating"), each = 100),
                    "t" = rep(1:100, 2))
  plt_df$cond = factor(plt_df$cond, levels = c("healthy", "regenerating"))
  pltreg = ggplot(plt_df, aes(x = t, y = exp, group = cond, col = cond))+
    geom_line(size = 1.5)+
    labs(x = "zonation", y = "Expression", title = g)+
    scale_colour_manual(values = colcond)+
    geneplot_theme
  print(cowplot::plot_grid(pltemb, pltreg, ncol = 2))
  
  plt_gene_list[[g]] = list("embolised" = pltemb, "regenerating" = pltreg)
}
for(g in names(plt_gene_list)){
  for(n in names(plt_gene_list[[g]])){
    pdf(paste0("figure_panels/fig3/hep_zon_", g, "_",  n, ".pdf"), 
        height = 2.2, width = 2.5, useDingbats = F)
    print(plt_gene_list[[g]][[n]])
    dev.off()
  }
}

Plot individual genes with all three conditions

plt_3_list = list()
for(g in g_list){
  plt_df = data.frame("exp" = c(hep_sig_fits$healthy[,g], hep_sig_fits$embolised[,g],
                                hep_sig_fits$regenerating[,g]),
                    "cond" = rep(c("healthy", "embolised", "regenerating"), each = 100),
                    "t" = rep(1:100, 3))
  plt_df$cond = factor(plt_df$cond, levels = c("healthy", "embolised", "regenerating"))
  plt_3_list[[g]] = ggplot(plt_df, aes(x = t, y = exp, group = cond, col = cond))+
    geom_line(size = 1.5)+
    labs(x = "zonation", y = "Expression", title = g, colour = "Condition")+
    scale_colour_manual(values = colcond)+
    guides(colour = guide_legend(title.position = "top"))+
    geneplot_theme
}

for(g in names(plt_3_list)){
  pdf(paste0("figure_panels/fig3/hep_zon_", g, "_all.pdf"), 
      height = 2.5, width = 3, useDingbats = F)
  print(plt_3_list[[g]])
  dev.off()
}

Plot mean profiles

for(n in names(hep_res_list)){
  plot_df2 = hep_res_list[[n]]$df
  xxx = plot_df2[plot_df2$cond=="difference",]
  labsdf = data.frame(labs = c("higher in\nhealthy", paste0("higher in\n", n)), coord = c(0.5, -0.5))
  plt1 = ggplot(xxx, aes(x = Var1, y = value))+
      facet_grid(~cls, scales = "free")+
      geom_hline(yintercept = 0, colour = "grey60", size = 0.75, linetype = "dashed")+
      stat_summary(fun.data=mean_cl_boot, colour="grey40", alpha = 0.35, geom="linerange", group=1)+
      stat_summary(fun=mean, colour="black", geom="line", group=1)+
      labs(x = "zonation", y = "difference in\nscaled expression")+
      scale_y_continuous(limits = c(-1,1))+
      theme_bw()+
      theme(axis.text = element_text(colour = "black", size = 7),
            axis.title = element_text(size = 8))
  plt2 = ggplot()+
    geom_text(data = labsdf, mapping = aes(y = coord, label = labs), 
              x = 0.5, angle = 270, size = 3)+
    scale_x_continuous(limits = c(0,1))+
    scale_y_continuous(limits = c(-1,1))+
    cowplot::theme_nothing()
  plt = cowplot::plot_grid(plt1, plt2, ncol = 2, nrow = 1, rel_widths = c(1, 0.085), align = "hv")
  
  pdf(paste0("figure_panels/fig3/hep_zon_", n, "_mean.pdf"), height = 1.8, width = 6, useDingbats = F)
  print(plt)
  dev.off()
}

Plot heatmaps

# get profiles for plotting
usegenes = unique(c(as.character(hep_res_list$embolised$df$Var2),
                    as.character(hep_res_list$regenerating$df$Var2)))

bins_list = list()
for(n in names(hep_cells)){
  plot_df = cbind(data.frame("pt" = rep(1:10, each = 10)),hep_sig_fits[[n]][,usegenes])
  plot_df$bins10 = cut(plot_df$pt, 10)
  bins_list[[n]] = sapply(usegenes, function(x) scale(tapply(plot_df[,x], 
                                                             plot_df$bins10, mean))[10:1])
}
bins_mean = Reduce(rbind, bins_list)
colnames(bins_mean) = usegenes

# choose genes for plotting
ecl_genes = merge(unique(hep_res_list$embolised$df[,c(1,4)]), hep_fits_qval$embolised$fdr, 
                  by.x = 1,  by.y = 0)
top_e = ecl_genes %>% group_by(cls) %>% slice_min(order_by = pval_list, n = 5)
emb_heat = pheatmap(bins_mean[1:20,as.character(top_e$Var2)], show_rownames = F, 
                    fontsize_col = 6.2, border_color = NA, gaps_row = c(10,20), gaps_col = seq(5, 20, 5), 
                    clustering_method = "ward.D2", cluster_rows = F, cluster_cols = F, fontsize = 6)
pdf("figure_panels/fig3/heatmap_zonation_emb.pdf", height=2.5, width=3.8, useDingbats = F)
print(emb_heat)
dev.off()
write.csv(ecl_genes, file = "figure_panels/fig3/hep_embolised_clusters_fdr.csv", row.names = F, quote = F)

rcl_genes = merge(unique(hep_res_list$regenerating$df[,c(1,4)]), hep_fits_qval$regenerating$fdr, 
                  by.x = 1,  by.y = 0)
top_r = rcl_genes %>% group_by(cls) %>% slice_min(order_by = pval_list, n = 5)
reg_heat = pheatmap(bins_mean[c(1:10, 21:30),as.character(top_r$Var2)], show_rownames = F, 
                    fontsize_col = 7.5, border_color = NA, gaps_row = c(10,20), gaps_col = seq(5, 20, 5), 
                    clustering_method = "ward.D2", cluster_rows = F, cluster_cols = F, fontsize = 6.7)
pdf("figure_panels/fig3/heatmap_zonation_reg.pdf", height=2.5, width=3.8, useDingbats = F)
print(reg_heat)
dev.off()
write.csv(rcl_genes, file = "figure_panels/fig3/hep_regen_clusters_fdr.csv", row.names = F, quote = F)

Figure 4

Main Figure

Load data

only_end_cells = readRDS(file = "results/endothelial/only_end_cells_zon.RDS")
all_cor_end = read.csv("results/endothelial/correlations_zonation_endothelial.csv", 
                       header = T, row.names = 1)
end_fits_qval = readRDS(file = "results/endothelial/end_fits_qval.RDS")
mksimp = read.csv("results/endothelial/markers_endo_subpop_simp.csv", header = T, row.names = 1)
mksimp = mksimp[order(mksimp$avg_logFC, decreasing = T),]

top_genes = readRDS(file = "results/cond_effect/top_genes_mk.RDS")

go_end = readRDS("results/endothelial/GOTerms_correlations.RDS")

endo_col = c("Periportal LSEC" = "aquamarine2",  "Midzonal LSEC" = "aquamarine3",
             "Pericentral LSEC" = "aquamarine4", "LSEC (fenestr.)" = "darkslategray1",
             "LSEC (remodelling)" = "cyan4", "LSEC (interferon)" = "darkslateblue",
             "LSEC (high MT 1)" = "blueviolet", "LSEC (high MT 2)" = "darkviolet",
             "LSEC (stress)" = "lightblue", "EC non-LSEC" = "forestgreen", 
             "Lymphatic EC" = "chartreuse3", "Cycling cells" = "grey20")

UMAPs

only_end_cells = readRDS(file = "results/endothelial/only_end_cells_zon.RDS")
all_cor_end = read.csv("results/endothelial/correlations_zonation_endothelial.csv", 
                       header = T, row.names = 1)
end_fits_qval = readRDS(file = "results/endothelial/end_fits_qval.RDS")
mksimp = read.csv("results/endothelial/markers_endo_subpop_simp.csv", header = T, row.names = 1)
mksimp = mksimp[order(mksimp$avg_logFC, decreasing = T),]

top_genes = readRDS(file = "results/cond_effect/top_genes_mk.RDS")

go_end = readRDS("results/endothelial/GOTerms_correlations.RDS")

Frequency tables

df_cnt = table(only_end_cells$endo_simp, only_end_cells$Condition)
df_cnt_perCond = reshape2::melt(apply(df_cnt, 2, function(x) round(x/sum(x)*100, 1)))
df_cnt_perCl = reshape2::melt(apply(df_cnt, 1, function(x) round(x/sum(x)*100, 1)))

mat_cnt_all = reshape2::dcast(data = df_cnt_perCl, formula = Var1 ~ Var2, value.var = "value")
rownames(mat_cnt_all) = mat_cnt_all$Var1
mat_cnt_all = t(mat_cnt_all[,-1])
ctord = hclust(dist(mat_cnt_all[,c(2,1,3)]))$order

heatp = pheatmap::pheatmap(mat_cnt_all[ctord,c(2,1,3)], cluster_cols = F, cluster_rows = F, 
                           treeheight_row = F, display_numbers = T, fontsize_number = 7, 
                           number_color = c("black", "white")[as.integer(mat_cnt_all[ctord,c(2,1,3)]>50)+1],
                           color = colorRampPalette(brewer.pal(n = 9, name = "Blues"))(100),
                           fontsize_row = 7.5, fontsize_col = 7.5, angle_col = 0)

pdf("figure_panels/fig_endo/cluster_proportion_cond.pdf", height=3.2, width=3.3, useDingbats = F)
print(heatp)
dev.off()

Markers

mkplot = c("MGP", "AQP1", "CLEC14A", "EDNRB", "CLEC1B", "CLEC4G", "PLVAP", 
           "RBP7", "ANGPT2", "CTGF", "ISG15", "IFIT3", "MRO", "EGR1","PTGDS", "INMT", 
           "PROX1", "CCL21", "TOP2A")
mkplot = c("MGP", "AQP1", "CLEC14A", "IGFBP7", "CLEC1B", "CLEC4G", "PLVAP", 
           "RBP7", "ANGPT2", "CTGF", "ISG15", "IFIT3", "MRO", "EGR1","PTGDS", "INMT", 
           "PROX1", "CCL21", "TOP2A")

expdf = reshape2::melt(cbind(data.frame(Matrix::t(only_end_cells@assays$SCT@data[mkplot,]),
                                        "endo_simp" = only_end_cells$endo_simp)))
expdf$endo_simp = factor(expdf$endo_simp, levels = names(endo_col))

vioplt = ggplot(expdf, aes(x = endo_simp, y = value, fill = endo_simp))+
  facet_grid(variable~., scales = "free_y")+
  geom_violin(scale = "width", colour = "grey82", size = 0.35)+
  scale_fill_manual(values = endo_col)+
  scale_y_continuous(breaks = c(0, 2, 4))+
  labs(y = "Expression")+
  theme(legend.position = "none",
        axis.text.x = element_text(angle = -30, hjust = 0, vjust = 0.9),
        axis.title.x = element_blank(),
        axis.text.y = element_text(size = 6.5),
        axis.ticks = element_line(),
        strip.text.y = element_text(angle = 0, size = 7, margin = margin(0,0,0,0)),
        strip.background = element_rect(colour = "white", fill = "white"))

pdf("figure_panels_rev1/fig_endo/violins_mk_2.pdf", height=5.8, width=3.4, useDingbats = F)
print(vioplt)
dev.off()

boxplt = ggplot(expdf, aes(x = endo_simp, y = value, fill = endo_simp))+
  facet_grid(variable~., scales = "free_y")+
  geom_boxplot(colour = "grey50", outlier.shape = NA, size = 0.25)+
  scale_fill_manual(values = endo_col)+
  scale_y_continuous(breaks = c(0, 2, 4))+
  labs(y = "Expression")+
  theme(legend.position = "none",
        axis.text.x = element_text(angle = -30, hjust = 0, vjust = 0.9),
        axis.title.x = element_blank(),
        axis.text.y = element_text(size = 6.5),
        axis.ticks = element_line(),
        strip.text.y = element_text(angle = 0, size = 7, margin = margin(0,0,0,0)),
        strip.background = element_rect(colour = "white", fill = "white"))

pdf("figure_panels_rev1/fig_endo/boxes_mk_2.pdf", height=5.8, width=3.4, useDingbats = F)
print(boxplt)
dev.off()

Binned zonation

mkplot = c("MGP", "AQP1", "CLEC14A", "IGFBP7", "CLEC1B", "CLEC4M", "PLVAP", 
           "RBP7", "ANGPT2", "CTGF", "ISG15", "IFIT3", "MRO", "EGR1","PTGDS", "INMT", 
           "PROX1", "CCL21", "TOP2A")

expdf = reshape2::melt(cbind(data.frame(Matrix::t(only_end_cells@assays$SCT@data[mkplot,]),
                                        "endo_simp" = only_end_cells$endo_simp)))
Using endo_simp as id variables
expdf$endo_simp = factor(expdf$endo_simp, levels = names(endo_col))

vioplt = ggplot(expdf, aes(x = endo_simp, y = value, fill = endo_simp))+
  facet_grid(variable~., scales = "free_y")+
  geom_violin(scale = "width", colour = "grey82", size = 0.35)+
  scale_fill_manual(values = endo_col)+
  scale_y_continuous(breaks = c(0, 2, 4))+
  labs(y = "Expression")+
  theme(legend.position = "none",
        axis.text.x = element_text(angle = -30, hjust = 0, vjust = 0.9),
        axis.title.x = element_blank(),
        axis.text.y = element_text(size = 6.5),
        axis.ticks = element_line(),
        strip.text.y = element_text(angle = 0, size = 7, margin = margin(0,0,0,0)),
        strip.background = element_rect(colour = "white", fill = "white"))

Donor distributions

end_df = only_end_cells@meta.data[only_end_cells$goodcl,]

end_df = data.frame(vals = end_df$zonation_pt, 
                    Condition = end_df$Condition,
                    Donor = end_df$Donor,
                    ct = end_df$endo_simp)
end_df$bins10 = cut(end_df$vals, 10)
end_df$Condition = factor(end_df$Condition, levels = c("healthy", "regenerating", "embolised"))
end_df$Donor = factor(end_df$Donor)
end_df$Donor = plyr::revalue(end_df$Donor, c("HD1" = "sc_H1", "HD2" = "sc_H2", "HD3" = "sc_H3", 
                                             "DD1" = "sc_R1/E1", "DD2" = "sc_R2/E2", "DD3" = "sc_R3/E3",
                                             "DD5" = "sc_R4/E4", "DD6" = "sc_R5/E5", "DD7" = "sc_R6/E6"))
end_df$Donor = factor(end_df$Donor, levels = levels(end_df$Donor)[c(7:9, 1:6)])

end_don = ggplot(end_df, aes(x = vals, colour = Condition))+
  facet_wrap(~Donor, scales = "free_y")+
  geom_hline(yintercept = 0)+
  geom_density(size = 1.05)+
  labs(x = "Zonation", y = "Cell density")+
  scale_colour_manual(values = colcond)+
  scale_y_continuous(expand = c(0,0))+
  coord_flip()+
  guides(colour = guide_legend(title.position = "left", ncol = 3))+
  theme(axis.text.y = element_blank(),
        axis.ticks.x = element_line(),
        strip.text = element_text(margin = margin(0.04,0,0.04,0, "cm"), size = 7.5),
        strip.background = element_rect(fill = "white", colour = "white"),
        legend.title.align = 0,
        aspect.ratio = 0.8,
        legend.position = "bottom",
        legend.box.margin = margin(0,0,0,0),
        legend.box.spacing = unit(0.05, "cm"))

pdf("figure_panels/fig_endo/end_zonation_DonorsCond.pdf", height = 3.8, width = 3.4, useDingbats = F)
print(end_don)
dev.off()

Predicted zonation for other populations

plot_df = only_end_cells@meta.data[only_end_cells@meta.data$endo_simp %in% names(endo_col)[1:9],]
plot_df$bins100 = cut(plot_df$zonation_pt, 10)
plot_df$Condition = factor(plot_df$Condition, levels = c("healthy", "embolised", "regenerating"))
plot_df$endo_simp = factor(plot_df$endo_simp, levels = names(endo_col))

plot_ptall = ggplot(plot_df, aes(y = zonation_pt, x = endo_simp, fill = Condition))+
  facet_wrap(~endo_simp, scales = "free_x", ncol = 3)+
  geom_violin()+
  labs(y = "zonation", x = "clusters")+
  scale_y_continuous(expand = c(0,0), breaks = c(0, 0.25, 0.5, 0.75, 1), limits = c(0,1))+
  scale_fill_manual(values = colcond)+
  guides(fill = guide_legend(title.position = "left"))+
  theme_bw()+
  theme(axis.text.x = element_blank(),
        axis.ticks.x = element_blank(),
        axis.text.y = element_text(colour = "black", size = 7),
        axis.title = element_text(size = 8),
        strip.background = element_rect(fill = "white", colour = "black"),
        strip.text = element_text(size = 8),
        legend.title = element_blank(),
        legend.key.size = unit(0.3, "cm"),
        legend.box.spacing = unit(0.01, "cm"),
        legend.position = "bottom")

pdf("figure_panels/fig_endo/zonation_allLSEC.pdf", height=3.5, width=3.85, useDingbats = F)
print(plot_ptall)
dev.off()

Heatmap

only_end_cells_split = SplitObject(only_end_cells[,only_end_cells$goodcl], split.by = "Condition")

# filter markers from other cell types (can contaminate)
mk_others = unique(unlist(top_genes$cell_type[!grepl("LSEC ", names(top_genes$cell_type))]))
cor_sub = all_cor_end[!(all_cor_end$gene %in% mk_others),]

topgenes = unique(c(cor_sub$gene[order(cor_sub$HvE, decreasing = T)][1:30],
                    cor_sub$gene[order(cor_sub$HvR, decreasing = T)][1:30]))
bottomgenes = unique(c(cor_sub$gene[order(cor_sub$HvE, decreasing = F)][1:35],
                    cor_sub$gene[order(cor_sub$HvR, decreasing = F)][1:35]))

usegenes = c(topgenes, bottomgenes)

bins_list = list()
for(n in names(only_end_cells_split)){
  plot_df = cbind(data.frame("pt" = rep(1:10, each = 10)),end_fits_qval[[n]]$fits[,usegenes])
  plot_df$bins10 = cut(plot_df$pt, 10)
  bins_list[[n]] = sapply(usegenes, function(x) scale(tapply(plot_df[,x], 
                                                             plot_df$bins10, mean))[10:1])
}
bins_mean = Reduce(rbind, bins_list)

hct = hclust(dist(t(bins_list$healthy[,topgenes])), method = "ward.D2")
hcb = hclust(dist(t(bins_mean[,bottomgenes])), method = "ward.D2")
ord = c(topgenes[hct$order], bottomgenes[hcb$order])
cutb = factor(cutree(hcb, 10)[hcb$order], levels = unique(cutree(hcb, 8)[hcb$order]))

gaps = cumsum(table(cutb))[-10]+length(topgenes)

heat_plt = pheatmap(bins_mean[,ord], show_rownames = F, fontsize_col = 6.2, border_color = NA,
                    gaps_row = c(10,20), gaps_col = c(length(topgenes), gaps),
                    clustering_method = "ward.D2", cluster_rows = F, cluster_cols = F)

pdf("figure_panels/fig_endo/heatmap_corZon.pdf", height=3, width=7.8, useDingbats = F)
print(heat_plt)
dev.off()

GO Terms

go_theme = theme_bw()+
  theme(axis.text = element_text(colour = "black", size = 7.5),
        axis.title = element_text(size = 8),
        plot.title = element_text(size = 9),
        plot.title.position = "plot",
        plot.subtitle = element_text(size = 7.5),
        axis.text.y = element_text(vjust = 0.6, colour = c("grey45", "grey17")),
        panel.grid.major.y = element_blank())

gopltFunc = function(plot_df, tit = "", subtit = ""){
  plot_df$Description = breakStr(plot_df$Description, 30)
  plot_df$Description = factor(plot_df$Description, levels = rev(plot_df$Description))
  plot_df$fill = as.character(rep(1:2, ceiling(nrow(plot_df)/2)))[1:nrow(plot_df)]
  plt = ggplot(plot_df, aes(x = -log10(qvalue), y = Description, fill = fill))+
    geom_col(show.legend = F)+
    scale_x_continuous(expand = c(0,0), lim = c(0, max(-log10(plot_df$qvalue))+1))+
    scale_fill_manual(values = c("grey17", "grey45"))+
    labs(title = tit, subtitle = subtit)+
    go_theme
  return(plt)
}

pdf("figure_panels/fig_endo/end_go_emb_corr.pdf", height = 3.2, width = 3.6, useDingbats = F)
print(gopltFunc(go_end$cor_he, tit = "GO Terms - Embolised", subtit = "cor >= 0.3"))
dev.off()

pdf("figure_panels/fig_endo/end_go_reg_corr.pdf", height = 3.2, width = 3.6, useDingbats = F)
print(gopltFunc(go_end$cor_hr, tit = "GO Terms - Regenerating", subtit = "cor >= 0.3"))
dev.off()

Figure 5

Main Figure

Total interactions per cell type in each condition

net_names_l = readRDS(file = "results/cell_comm/updt/count_net_list.RDS")
# list per condition with interactions, genes, mean
reform_list = readRDS(file = "results/cell_comm/updt/reform_list.RDS")
# list per cond with ligand or receptor expression for each interaction
scoring_mats = readRDS(file = "results/cell_comm/updt/scoring_mats.RDS")
# reform_list + DE info + uniqueness/specificity of interaction/ligand/receptor
inter_df = readRDS(file = "results/cell_comm/updt/cond_diff_interact_DE.RDS")
# interactions qith certain functions involving which cell types and in which conditions
ct_g_cond_ann = readRDS(file = "results/cell_comm/updt/ct_g_cond_ann.RDS")
# interaction with L and R, pair of cell types, mean exp, and function
ct_int_exp_l = readRDS(file = "results/cell_comm/updt/interact_celltype_exp_group_list.RDS")
# annotation for all interactions
inter_annot = read.csv("data/interaction_annotation.csv", header = T)
inter_annot$funct[grepl("imm", inter_annot$funct)] = "immune"
inter_annot$funct[grepl("inflam", inter_annot$funct)] = "immune"
# mut info data
her_allint = readRDS(file = "./results/cell_comm/updt/interactions_mutInfo_condComp.RDS")
# GSEA on mutual info results
all_gsea_list = readRDS(file = "./results/cell_comm/updt/allgsea_interactions_mutInfo_condComp.RDS")
simp_gsea_list = readRDS(file = "./results/cell_comm/updt/simpgsea_interactions_mutInfo_condComp.RDS")
# network data
load("results/cell_comm/updt/median_networks_cond.RData")
load("results/cell_comm/updt/networks_cond.RData")
load("results/cell_comm/updt/median_networks_cond_midct.RData")
load("results/cell_comm/updt/median_networks_cond_umap.RData")
load("results/cell_comm/updt/networks_cond_umap.RData")
load("results/cell_comm/updt/median_networks_cond_umap_midct.RData")
comph_inters = readRDS(file = "results/cell_comm/updt/comph_inters.RDS")

Plot changes in number of interactions per condition

net_names_l = readRDS(file = "results/cell_comm/updt/count_net_list.RDS")

# list per condition with interactions, genes, mean
reform_list = readRDS(file = "results/cell_comm/updt/reform_list.RDS")
# list per cond with ligand or receptor expression for each interaction
scoring_mats = readRDS(file = "results/cell_comm/updt/scoring_mats.RDS")
# reform_list + DE info + uniqueness/specificity of interaction/ligand/receptor
inter_df = readRDS(file = "results/cell_comm/updt/cond_diff_interact_DE.RDS")
# interactions qith certain functions involving which cell types and in which conditions
ct_g_cond_ann = readRDS(file = "results/cell_comm/updt/ct_g_cond_ann.RDS")
# interaction with L and R, pair of cell types, mean exp, and function
ct_int_exp_l = readRDS(file = "results/cell_comm/updt/interact_celltype_exp_group_list.RDS")
# annotation for all interactions
inter_annot = read.csv("data/interaction_annotation.csv", header = T)
inter_annot$funct[grepl("imm", inter_annot$funct)] = "immune"
inter_annot$funct[grepl("inflam", inter_annot$funct)] = "immune"
# mut info data
her_allint = readRDS(file = "./results/cell_comm/updt/interactions_mutInfo_condComp.RDS")
# GSEA on mutual info results
all_gsea_list = readRDS(file = "./results/cell_comm/updt/allgsea_interactions_mutInfo_condComp.RDS")
simp_gsea_list = readRDS(file = "./results/cell_comm/updt/simpgsea_interactions_mutInfo_condComp.RDS")
# network data
load("results/cell_comm/updt/median_networks_cond.RData")
load("results/cell_comm/updt/networks_cond.RData")
load("results/cell_comm/updt/median_networks_cond_midct.RData")
load("results/cell_comm/updt/median_networks_cond_umap.RData")
load("results/cell_comm/updt/networks_cond_umap.RData")
load("results/cell_comm/updt/median_networks_cond_umap_midct.RData")
comph_inters = readRDS(file = "results/cell_comm/updt/comph_inters.RDS")

Non-ubiquitous interaction functions per cell type and condition

# correct some names
reform_list_int = list()
for(n in names(reform_list)[1:3]){
  reform_list[[n]]$ct1[grepl("Hepa", reform_list[[n]]$ct1)] = "Hepatocytes"
  reform_list[[n]]$ct2[grepl("Hepa", reform_list[[n]]$ct2)] = "Hepatocytes"
  reform_list[[n]]$ct1[grepl("LSEC_", reform_list[[n]]$ct1)] = "LSEC"
  reform_list[[n]]$ct2[grepl("LSEC_", reform_list[[n]]$ct2)] = "LSEC"
  reform_list_int[[n]] = reform_list[[n]][reform_list[[n]]$ct1!="Dividing cells" &
                                            reform_list[[n]]$ct2!="Dividing cells",]
  reform_list_int[[n]] = reform_list_int[[n]][!duplicated(reform_list_int[[n]][,1:3]),1:3]
}

# count interactions
infer_df = data.frame(expand.grid(unique(reform_list_int$healthy$ct1), 
                                  unique(reform_list_int$healthy$ct1)))
nr = nrow(infer_df)
infer_df = rbind(infer_df, infer_df, infer_df)
infer_df$count = 0
infer_df$cond = rep(names(reform_list)[1:3], each = nr)
colnames(infer_df)[1:2] = c("SOURCE", "TARGET")
for(i in 1:nrow(infer_df)){
  tmp = reform_list_int[[infer_df[i,4]]]
  infer_df[i,3] = dim(tmp[(tmp$ct1==infer_df[i,1] & tmp$ct2==infer_df[i,2]) |
                            (tmp$ct2==infer_df[i,1] & tmp$ct1==infer_df[i,2]),])[1]
}
## make one to count over all
infer_all = data.frame(expand.grid(unique(reform_list_int$healthy$ct1), 
                                   unique(reform_list_int$healthy$ct1)))
infer_all$count = 0
colnames(infer_all)[1:2] = c("SOURCE", "TARGET")
reform_all_int = unique(Reduce(rbind, reform_list_int))
for(i in 1:nrow(infer_all)){
  infer_all[i,3] = infer_all[i,3]+dim(tmp[(reform_all_int$ct1==infer_all[i,1] & reform_all_int$ct2==infer_all[i,2]) |
                                            (reform_all_int$ct2==infer_all[i,1] & reform_all_int$ct1==infer_all[i,2]),])[1]
}

infer_df_list = list(healthy = infer_df[infer_df$cond=="healthy",],
                     embolised = infer_df[infer_df$cond=="embolised",],
                     regenerating = infer_df[infer_df$cond=="regenerating",],
                     all = infer_all)

net_names_all = t(Reduce(rbind, lapply(infer_df_list[1:3], function(x) tapply(x$count, x$SOURCE, sum))))
colnames(net_names_all) = names(net_names_l)[1:3]
net_names_all = reshape2::melt(net_names_all)
net_names_all$Var1 = factor(net_names_all$Var1, 
                            levels = net_names_all[net_names_all$Var2=="healthy","Var1"][order(net_names_all[net_names_all$Var2=="healthy","value"], decreasing = F)])

total_unique = data.frame(t(t(Reduce(rbind, lapply(infer_df_list[4], 
                                                   function(x) tapply(x$count, x$SOURCE, sum))))))
total_unique$Var1 = rownames(total_unique)
colnames(total_unique)[1] = "value"
total_unique$Var2 = "total unique"

net_names_all$Var1 = factor(net_names_all$Var1, 
                            levels = total_unique$Var1[order(total_unique$value, 
                                                             decreasing = F)])
plt_counts = ggplot(net_names_all, aes(x = Var1, y = value))+
  geom_point(mapping = aes(colour = Var2), size = 1.6)+
  geom_point(data = total_unique, mapping = aes(shape = Var2), size = 1.6)+
  coord_flip()+
  scale_colour_manual(values = colcond)+
  scale_shape_manual(values = c(4))+
  scale_y_continuous(expand = c(0,0), limits = c(0,6500))+
  labs(y = "Total interactions", x = "Cell Type", colour = "Condition")+
  guides(colour = guide_legend(order = 1), shape = guide_legend(order = 2, title = NULL))+
  theme_bw()+
  theme(axis.text.x = element_text(angle = 30, vjust = 1, hjust = 1),
        axis.text = element_text(colour = "black"),
        axis.title.x = element_text(size = 8),
        legend.margin = margin(1, 1, 1, 1),
        legend.spacing.x = unit(0.05, "cm"),
        legend.direction = "horizontal",legend.box = "horizontal")
leg = cowplot::get_legend(plt_counts)

perc_df = data.frame("Var1" = net_names_all$Var1,
                     "Var2" = net_names_all$Var2,
                     "perc" = c(rep(0, length(unique(net_names_all$Var1))),
                                (net_names_all$value[net_names_all$Var2=="embolised"]-net_names_all$value[net_names_all$Var2=="healthy"])/net_names_all$value[net_names_all$Var2=="healthy"],
                                (net_names_all$value[net_names_all$Var2=="regenerating"]-net_names_all$value[net_names_all$Var2=="healthy"])/net_names_all$value[net_names_all$Var2=="healthy"])*100)
perc_df$col = ifelse(perc_df$perc>0, "green", "red")
perc_df = perc_df[perc_df$Var2!="healthy",]

perc_plt_emb = ggplot(perc_df[perc_df$Var2=="embolised",], aes(x = Var1, y = perc, fill = col))+
  geom_col()+
  scale_fill_manual(values = c("deepskyblue1", "red1"))+
  scale_y_continuous(expand = c(0,0), limits = c(-45,70))+
  coord_flip()+
  labs(y = "% change\nembolised vs healthy", x = "Cell Type")+
  theme_bw()+
  theme(axis.text.x = element_text(angle = 30, vjust = 1, hjust = 1, colour = "black"),
        axis.text.y = element_blank(),
        axis.title.x = element_text(size = 8),
        axis.title.y = element_blank(),
        axis.ticks.y = element_blank(),
        legend.position = "none")
perc_plt_reg = ggplot(perc_df[perc_df$Var2=="regenerating",], aes(x = Var1, y = perc, fill = col))+
  geom_col()+
  scale_fill_manual(values = c("deepskyblue1", "red1"))+
  scale_y_continuous(expand = c(0,0), limits = c(-45,70))+
  coord_flip()+
  labs(y = "% change\nregenerating vs healthy", x = "Cell Type")+
  theme_bw()+
  theme(axis.text.x = element_text(angle = 30, vjust = 1, hjust = 1, colour = "black"),
        axis.text.y = element_blank(),
        axis.title.x = element_text(size = 8),
        axis.title.y = element_blank(),
        axis.ticks.y = element_blank(),
        legend.position = "none")

cowplot::plot_grid(cowplot::plot_grid(plt_counts+theme(legend.position = "none"), 
                                      perc_plt_emb, perc_plt_reg, 
                                      ncol = 3, align = "h", axis = "r", rel_widths = c(1,0.5,0.5)),
                   leg, nrow = 2, rel_heights = c(1, 0.1))

pdf("figure_panels_rev1/fig_comm/mainFig_countsCond.pdf", height = 7, width = 7)
cowplot::plot_grid(cowplot::plot_grid(plt_counts+theme(legend.position = "none"), 
                                      perc_plt_reg, perc_plt_emb, 
                                      ncol = 3, align = "h", axis = "r", rel_widths = c(1,0.4,0.4)),
                   leg, nrow = 2, rel_heights = c(1, 0.1))
dev.off()
png 
  2 

Interaction functions per cell type and condition (using all interactions)

# interactions have to be absent in at least one condition
plot_df = ct_g_cond_ann[ct_g_cond_ann$celltypes %in% c("Stellate cells", "LSEC", "Kupffer cells", "cDCs",
                                                       "pDCs", "Endothelial cells (non-LSEC)") & 
                          ct_g_cond_ann$description %in% c("ECM", "inflammation", "migration",
                                                           "development", "immune activity", 
                                                           "immune suppression", "immune regulation"),]
plot_df$description = gsub(" ", "\n", plot_df$description, fixed = T)
plot_df$celltypes = gsub(" (", "\n(", plot_df$celltypes, fixed = T)
plot_df$description[grepl("immune", plot_df$description) | 
                      grepl("inflamm", plot_df$description)] = "immune"
bar_func_sub = ggplot(plot_df, aes(x = condition, fill = condition))+
  facet_grid(celltypes~description, scales = "free_y")+
  geom_bar()+
  scale_fill_manual(values = colcond)+
  theme_classic()+
  theme(axis.text.x = element_text(angle = 45, hjust = 1, vjust = 1, size = 7, colour = "black"),
        axis.text.y = element_text(size = 6.3, colour = "black"),
        axis.title = element_text(size = 7),
        axis.line = element_blank(),
        panel.background = element_rect(colour = "black"),
        panel.grid.major.y = element_line(),
        strip.text = element_text(size = 7),
        strip.background = element_blank(),
        aspect.ratio = 1,
        legend.position = "none")

pdf("figure_panels_rev1/fig_comm/mainFig_funcPart.pdf", height = 5.5, width = 4.5)
print(bar_func_sub)
dev.off()
null device 
          1 
plot_df = ct_g_cond_ann
plot_df$description = gsub(" ", "\n", plot_df$description, fixed = T)
plot_df$celltypes = gsub(" (", "\n(", plot_df$celltypes, fixed = T)
plot_df$description[grepl("immune", plot_df$description) | 
                      grepl("inflamm", plot_df$description)] = "immune"
bar_func_all = ggplot(plot_df, aes(x = condition, fill = condition))+
  facet_grid(celltypes~description, scales = "free_y")+
  geom_bar()+
  scale_fill_manual(values = colcond)+
  theme_classic()+
  theme(axis.text.x = element_text(angle = 45, hjust = 1, vjust = 1, size = 7, colour = "black"),
        axis.text.y = element_text(size = 6.3, colour = "black"),
        axis.title = element_text(size = 7),
        axis.line = element_blank(),
        panel.background = element_rect(colour = "black"),
        panel.grid.major.y = element_line(),
        strip.text = element_text(size = 7),
        strip.background = element_blank(),
        aspect.ratio = 1/2,
        legend.position = "none")

pdf("figure_panels_rev1/fig_comm/suppFig_countsFunc.pdf", paper = "a4", width = 9, height = 13.5)
print(bar_func_all)
*** recursive gc invocation
*** recursive gc invocation
*** recursive gc invocation
*** recursive gc invocation
*** recursive gc invocation
*** recursive gc invocation
*** recursive gc invocation
*** recursive gc invocation
dev.off()
null device 
          1 

GSEA qvalue for changing interactions (using all)

plot_df = Reduce(rbind, reform_list[1:3])
plot_df$cond = c(rep("healthy", nrow(reform_list$healthy)), 
                 rep("embolised", nrow(reform_list$embolised)), 
                 rep("regenerating", nrow(reform_list$regenerating)))
plot_df = unique(plot_df)
plot_df = data.frame(rbind(as.matrix(plot_df[,c(1,2,8)]), as.matrix(plot_df[,c(1,3,8)])))
plot_df = merge(plot_df, inter_annot, by = 1, all.x = T)
colnames(plot_df) = c("interaction", "celltypes", "condition", "description")

plot_df$description = gsub(" ", "\n", plot_df$description, fixed = T)
plot_df$celltypes = gsub(" (", "\n(", plot_df$celltypes, fixed = T)
plot_df$description[grepl("immune", plot_df$description) | 
                      grepl("inflamm", plot_df$description)] = "immune"
bar_func_all = ggplot(plot_df, aes(x = condition, fill = condition))+
  facet_grid(description~celltypes, scales = "free_y")+
  geom_bar()+
  scale_fill_manual(values = colcond)+
  theme_classic()+
  theme(axis.text.x = element_text(angle = 45, hjust = 1, vjust = 1, size = 7, colour = "black"),
        axis.text.y = element_text(size = 6.3, colour = "black"),
        axis.title = element_text(size = 7),
        axis.line = element_blank(),
        panel.background = element_rect(colour = "black"),
        panel.grid.major.y = element_line(),
        strip.text = element_text(size = 7),
        strip.background = element_blank(),
        aspect.ratio = 1,
        legend.position = "none")

Interaction expression matrices

plot_df = Reduce(rbind, all_gsea_list)
plot_df$q.val = -log10(plot_df$q.val+0.0000005)*(plot_df$sscore/abs(plot_df$sscore))
plot_df$comp = factor(plot_df$comp, levels = rev(c("he","hr","er")))
m = tapply(plot_df$q.val, plot_df$group,mean)
plot_df$group = factor(plot_df$group, levels = names(m)[order(m, decreasing = F)])
plot_df = plot_df[plot_df$comp!="er",]
plot_df$comp = as.character(plyr::revalue(plot_df$comp, 
                                          c("hr" = "regenerating", "he" = "embolised", "er" = "nothing")))
plot_df$comp = factor(plot_df$comp, levels = c("regenerating", "embolised"))

gseaplt = ggplot(plot_df, aes(x = q.val, y = group, fill = comp))+
  geom_col(position = "dodge")+
  geom_vline(xintercept = c(log10(0.05), -log10(0.05)), linetype = "dashed")+
  geom_vline(xintercept = c(0))+
  scale_fill_manual(values = colcond, drop = T)+
  guides(fill = guide_legend(title = "healthy vs", reverse = T))+
  labs(x = "q-value x score signal", y = "interaction type", fill = "comparison")+
  theme_bw()+
  theme(axis.text = element_text(colour = "black", size = 7),
        axis.title = element_text(colour = "black", size = 7.5),
        legend.position = c(0,1),
        legend.justification = c(-0.05,1.05),
        legend.title = element_text(size = 7.5),
        legend.text = element_text(size = 7),
        legend.margin = margin(0,0,0,0),
        legend.key.size = unit(0.35, "cm"))

pdf("figure_panels_rev1/fig_comm/mainFig_funcGSEA.pdf", height = 2.2, width = 2.85)
print(gseaplt)
dev.off()
null device 
          1 

Network plots - MDS

pltboth = ggplot()+
  geom_point(data = point_cond_df, mapping = aes(x = X1, y = X2, colour = ct2), 
             alpha = 0.6, show.legend = NA, size = 1.3)+
  geom_segment(data = pe_l[[2]], 
               mapping = aes(x = X1.x, xend = X1.y, y = X2.x, yend = X2.y, size = Freq), 
               alpha = 0.15, show.legend = F)+
  geom_point(data = pe_l[[1]], 
             mapping = aes(x = X1, y = X2, fill = ct), 
             alpha = 1, pch = 21, size = 4)+
  guides(colour = guide_legend(override.aes = list(size = 2.3)))+
  scale_size_continuous(range = c(0, 4), limits = range(pe_l[[2]]$Freq))+
  scale_colour_manual(values = colsmajor)+
  #scale_fill_manual(values = colsallct)+
  theme_classic()+ 
  theme(aspect.ratio = 1, 
        axis.line = element_blank(),
        axis.text = element_blank(),
        axis.title = element_blank(),
        axis.ticks = element_blank(),
        legend.title = element_blank(),
        legend.key.size = unit(0.35, "cm"),
        legend.spacing.y = unit(0.1, "cm"),
        legend.position = "none")
pdf("figure_panels_rev1/fig_comm/mainFig_inet_cond_all.pdf", 
    height = 3.1, width = 5.2, useDingbats = F)
print(pltboth)
dev.off()

plt_cond_l_ch = list()
for(cc in unique(pe_cond_l_ch[[2]]$condition)){
  plt_cond_l_ch[[cc]] = ggplot()+
    geom_segment(data = pe_cond_l_ch[[2]][pe_cond_l_ch[[2]]$condition==cc,], 
                 mapping = aes(x = X1.x, xend = X1.y, y = X2.x, yend = X2.y, size = Freq, alpha = Freq))+
    geom_point(data = pe_cond_l_ch[[1]], 
               mapping = aes(x = X1, y = X2, fill = ct), 
               alpha = 1, pch = 21, size = 4)+
    scale_size_continuous(range = c(0, 4), limits = range(pe_cond_l_ch[[2]]$Freq))+
    scale_alpha_continuous(range = c(0, 1), limits = range(pe_cond_l_ch[[2]]$Freq))+
    #scale_fill_manual(values = colsallct)+
    labs(title = cc)+
    guides(size = guide_legend(direction = "horizontal", nrow = 2),
           alpha = guide_legend(direction = "horizontal", nrow = 2))+
    theme_classic()+ 
    theme(aspect.ratio = 1, 
          axis.line = element_blank(),
          axis.text = element_blank(),
          axis.title = element_blank(),
          axis.ticks = element_blank(),
          panel.background = element_rect(colour = "black"),
          legend.title = element_blank(),
          legend.key.size = unit(0.35, "cm"),
          legend.position = "none")
}
plt_cond_l_ch[["leg"]] = cowplot::get_legend(plt_cond_l_ch[["healthy"]])

pdf("figure_panels_rev1/fig_comm/mainFig_inet_cond_median.pdf", height = 3.2, width = 5, useDingbats = F)
print(plt_cond_l_ch$healthy)
print(plt_cond_l_ch$embolised)
print(plt_cond_l_ch$regenerating)
dev.off()

Network plots with middle cell type resolution - MDS

pltboth = ggplot()+
  geom_point(data = point_cond_df, mapping = aes(x = X1, y = X2, colour = ct2), 
             alpha = 0.6, show.legend = NA, size = 1.3)+
  geom_segment(data = pe_l[[2]], 
               mapping = aes(x = X1.x, xend = X1.y, y = X2.x, yend = X2.y, size = Freq), 
               alpha = 0.15, show.legend = F)+
  geom_point(data = pe_l[[1]], 
             mapping = aes(x = X1, y = X2, fill = ct), 
             alpha = 1, pch = 21, size = 4)+
  guides(colour = guide_legend(override.aes = list(size = 2.3)))+
  scale_size_continuous(range = c(0, 4), limits = range(pe_l[[2]]$Freq))+
  scale_colour_manual(values = colsmajor)+
  #scale_fill_manual(values = colsallct)+
  theme_classic()+ 
  theme(aspect.ratio = 1, 
        axis.line = element_blank(),
        axis.text = element_blank(),
        axis.title = element_blank(),
        axis.ticks = element_blank(),
        legend.title = element_blank(),
        legend.key.size = unit(0.35, "cm"),
        legend.spacing.y = unit(0.1, "cm"),
        legend.position = "none")
pdf("figure_panels_rev1/fig_comm/mainFig_inet_cond_all.pdf", 
    height = 3.1, width = 5.2, useDingbats = F)
print(pltboth)
dev.off()
null device 
          1 
plt_cond_l_ch = list()
for(cc in unique(pe_cond_l_ch[[2]]$condition)){
  plt_cond_l_ch[[cc]] = ggplot()+
    geom_segment(data = pe_cond_l_ch[[2]][pe_cond_l_ch[[2]]$condition==cc,], 
                 mapping = aes(x = X1.x, xend = X1.y, y = X2.x, yend = X2.y, size = Freq, alpha = Freq))+
    geom_point(data = pe_cond_l_ch[[1]], 
               mapping = aes(x = X1, y = X2, fill = ct), 
               alpha = 1, pch = 21, size = 4)+
    scale_size_continuous(range = c(0, 4), limits = range(pe_cond_l_ch[[2]]$Freq))+
    scale_alpha_continuous(range = c(0, 1), limits = range(pe_cond_l_ch[[2]]$Freq))+
    #scale_fill_manual(values = colsallct)+
    labs(title = cc)+
    guides(size = guide_legend(direction = "horizontal", nrow = 2),
           alpha = guide_legend(direction = "horizontal", nrow = 2))+
    theme_classic()+ 
    theme(aspect.ratio = 1, 
          axis.line = element_blank(),
          axis.text = element_blank(),
          axis.title = element_blank(),
          axis.ticks = element_blank(),
          panel.background = element_rect(colour = "black"),
          legend.title = element_blank(),
          legend.key.size = unit(0.35, "cm"),
          legend.position = "none")
}
plt_cond_l_ch[["leg"]] = cowplot::get_legend(plt_cond_l_ch[["healthy"]])

pdf("figure_panels_rev1/fig_comm/mainFig_inet_cond_median.pdf", height = 3.2, width = 5, useDingbats = F)
print(plt_cond_l_ch$healthy)
print(plt_cond_l_ch$embolised)
print(plt_cond_l_ch$regenerating)
dev.off()
null device 
          1 

Network plots - UMAP

pltboth = ggplot()+
  geom_point(data = point_cond_umap_df, mapping = aes(x = X1, y = X2, colour = ct2), 
             alpha = 0.6, show.legend = NA, size = 1.3)+
  geom_segment(data = pe_umap_l[[2]], 
               mapping = aes(x = X1.x, xend = X1.y, y = X2.x, yend = X2.y, size = Freq), 
               alpha = 0.15, show.legend = F)+
  geom_point(data = pe_umap_l[[1]], 
             mapping = aes(x = X1, y = X2, fill = ct), 
             alpha = 1, pch = 21, size = 4)+
  guides(colour = guide_legend(override.aes = list(size = 2.3)))+
  scale_size_continuous(range = c(0, 4), limits = range(pe_l[[2]]$Freq))+
  scale_colour_manual(values = colsmajor)+
  scale_fill_manual(values = colsallct)+
  theme_classic()+ 
  theme(aspect.ratio = 1, 
        axis.line = element_blank(),
        axis.text = element_blank(),
        axis.title = element_blank(),
        axis.ticks = element_blank(),
        legend.title = element_blank(),
        legend.key.size = unit(0.35, "cm"),
        legend.spacing.y = unit(0.1, "cm"),
        legend.position = "none")
pdf("figure_panels_rev1/fig_comm/mainFig_inet_cond_umap_all.pdf", height = 3.1, width = 5.2, useDingbats = F)
print(pltboth)
dev.off()

plt_cond_l_ch = list()
for(cc in unique(pe_umap_cond_l_ch[[2]]$cond)){
  plt_cond_l_ch[[cc]] = ggplot()+
    geom_segment(data = pe_umap_cond_l_ch[[2]][pe_umap_cond_l_ch[[2]]$cond==cc,], 
                 mapping = aes(x = X1.x, xend = X1.y, y = X2.x, yend = X2.y, size = Freq, alpha = Freq))+
    geom_point(data = pe_umap_cond_l_ch[[1]], 
               mapping = aes(x = X1, y = X2, fill = ct), 
               alpha = 1, pch = 21, size = 4)+
    scale_size_continuous(range = c(0, 4), limits = range(pe_umap_cond_l_ch[[2]]$Freq))+
    scale_alpha_continuous(range = c(0, 1), limits = range(pe_umap_cond_l_ch[[2]]$Freq))+
    scale_fill_manual(values = colsallct)+
    labs(title = cc)+
    guides(size = guide_legend(direction = "horizontal", nrow = 2),
           alpha = guide_legend(direction = "horizontal", nrow = 2))+
    theme_classic()+ 
    theme(aspect.ratio = 1, 
          axis.line = element_blank(),
          axis.text = element_blank(),
          axis.title = element_blank(),
          axis.ticks = element_blank(),
          panel.background = element_rect(colour = "black"),
          legend.title = element_blank(),
          legend.key.size = unit(0.35, "cm"),
          legend.position = "none")
}
plt_cond_l_ch[["leg"]] = cowplot::get_legend(plt_cond_l_ch[["healthy"]])

pdf("figure_panels_rev1/fig_comm/mainFig_inet_cond_umap_median.pdf", height = 3.2, width = 5, useDingbats = F)
print(plt_cond_l_ch$healthy)
print(plt_cond_l_ch$embolised)
print(plt_cond_l_ch$regenerating)
dev.off()

Network plots with middle cell type resolution - UMAP

pltboth = ggplot()+
  geom_point(data = point_cond_umap_df, mapping = aes(x = X1, y = X2, colour = ct2), 
             alpha = 0.6, show.legend = NA, size = 1.3)+
  geom_segment(data = pe_umap_l[[2]], 
               mapping = aes(x = X1.x, xend = X1.y, y = X2.x, yend = X2.y, size = Freq), 
               alpha = 0.15, show.legend = F)+
  geom_point(data = pe_umap_l[[1]], 
             mapping = aes(x = X1, y = X2, fill = ct), 
             alpha = 1, pch = 21, size = 4)+
  guides(colour = guide_legend(override.aes = list(size = 2.3)))+
  scale_size_continuous(range = c(0, 4), limits = range(pe_l[[2]]$Freq))+
  scale_colour_manual(values = colsmajor)+
  scale_fill_manual(values = colsallct)+
  theme_classic()+ 
  theme(aspect.ratio = 1, 
        axis.line = element_blank(),
        axis.text = element_blank(),
        axis.title = element_blank(),
        axis.ticks = element_blank(),
        legend.title = element_blank(),
        legend.key.size = unit(0.35, "cm"),
        legend.spacing.y = unit(0.1, "cm"),
        legend.position = "none")
pdf("figure_panels_rev1/fig_comm/mainFig_inet_cond_umap_all.pdf", height = 3.1, width = 5.2, useDingbats = F)
print(pltboth)
dev.off()
null device 
          1 
plt_cond_l_ch = list()
for(cc in unique(pe_umap_cond_l_ch[[2]]$cond)){
  plt_cond_l_ch[[cc]] = ggplot()+
    geom_segment(data = pe_umap_cond_l_ch[[2]][pe_umap_cond_l_ch[[2]]$cond==cc,], 
                 mapping = aes(x = X1.x, xend = X1.y, y = X2.x, yend = X2.y, size = Freq, alpha = Freq))+
    geom_point(data = pe_umap_cond_l_ch[[1]], 
               mapping = aes(x = X1, y = X2, fill = ct), 
               alpha = 1, pch = 21, size = 4)+
    scale_size_continuous(range = c(0, 4), limits = range(pe_umap_cond_l_ch[[2]]$Freq))+
    scale_alpha_continuous(range = c(0, 1), limits = range(pe_umap_cond_l_ch[[2]]$Freq))+
    scale_fill_manual(values = colsallct)+
    labs(title = cc)+
    guides(size = guide_legend(direction = "horizontal", nrow = 2),
           alpha = guide_legend(direction = "horizontal", nrow = 2))+
    theme_classic()+ 
    theme(aspect.ratio = 1, 
          axis.line = element_blank(),
          axis.text = element_blank(),
          axis.title = element_blank(),
          axis.ticks = element_blank(),
          panel.background = element_rect(colour = "black"),
          legend.title = element_blank(),
          legend.key.size = unit(0.35, "cm"),
          legend.position = "none")
}
plt_cond_l_ch[["leg"]] = cowplot::get_legend(plt_cond_l_ch[["healthy"]])

pdf("figure_panels_rev1/fig_comm/mainFig_inet_cond_umap_median.pdf", height = 3.2, width = 5, useDingbats = F)
print(plt_cond_l_ch$healthy)
print(plt_cond_l_ch$embolised)
print(plt_cond_l_ch$regenerating)
dev.off()
null device 
          1 

Heatmaps for interactions with immune cells

# interactions unique to healthy or to emb/regen
comph_inters = c(setdiff(inter_df$healthy$id_cp_interaction,
                         c(inter_df$embolised$id_cp_interaction, inter_df$regenerating$id_cp_interaction)),
                 setdiff(inter_df$embolised$id_cp_interaction, inter_df$healthy$id_cp_interaction),
                 setdiff(inter_df$regenerating$id_cp_interaction, inter_df$healthy$id_cp_interaction))

edge_min = edge_cond_df[,c(1:4,9:12)]
edge_min = merge(edge_min, unique(her_allint_f[,c(1,13)]), by.x = 3, by.y = 1, all.x = T)
edge_min = merge(edge_min, unique(her_allint_f[,c(1,17)]), by.x = 1, by.y = 1, all.x = T)
edge_min = edge_min[edge_min$maj_g1=="Immune" | edge_min$maj_g2=="Immune",]
edge_min = edge_min[edge_min$ct_g1!=edge_min$ct_g2,]
edge_min = edge_min[edge_min$id_cp_interaction %in% comph_inters,]

devdf = filtFunc(her_allint_f[her_allint_f$funct=="development",], expthr = 0.15)
ecmdf = filtFunc(her_allint_f[her_allint_f$funct=="ECM",], expthr = 0.15)

plot_df = filtFunc(her_allint_f[her_allint_f$id_cp_interaction %in% unique(edge_min$id_cp_interaction),],
                   expthr = 0.07, minct = 2)
plot_df = plot_df[!(plot_df$intlr %in% c(devdf$intlr, ecmdf$intlr)),]
imm_plt = pltFunc(plot_df)
pdf("figure_panels_rev1/fig_comm/mainFig_immuneNetInteract_many.pdf", height = 3, width = 20)
print(imm_plt)
dev.off()

plot_df = filtFunc(her_allint_f[her_allint_f$id_cp_interaction %in% unique(edge_min$id_cp_interaction),],
                   expthr = 0.3, minct = 2)
plot_df = plot_df[!(plot_df$intlr %in% c(devdf$intlr, ecmdf$intlr)),]
imm_plt = pltFunc(plot_df)
pdf("figure_panels_rev1/fig_comm/mainFig_immuneNetInteract.pdf", height = 2.86, width = 7.1)
print(imm_plt)
dev.off()

Heatmaps with number of interactions per condition

cnts_list = list()
tab_list = list()
for(n in names(inter_df)[1:3]){
  subdfct = unique(inter_df[[n]][,1:3])
  subdfct$ct1[grepl("LSEC_", subdfct$ct1)] = "LSEC"
  subdfct$ct2[grepl("LSEC_", subdfct$ct2)] = "LSEC"
  subdfct$ct1[grepl("Hepat", subdfct$ct1)] = "Hepatocytes"
  subdfct$ct2[grepl("Hepat", subdfct$ct2)] = "Hepatocytes"
  #subdfct$ct1[grepl("non-", subdfct$ct1)] = "Endothelial cells\n(non-LSEC)"
  #subdfct$ct2[grepl("non-", subdfct$ct2)] = "Endothelial cells\n(non-LSEC)"
  subdfct = unique(subdfct)
  dfct = table(data.frame("ct1" = c(subdfct$ct1, subdfct$ct2),
                          "ct2" = c(subdfct$ct2, subdfct$ct1)))
  hcl = hclust(dist(dfct), method = "ward.D2")
  plot_df = data.frame(dfct)
  plot_df$ct1 = factor(plot_df$ct1, levels = levels(net_names_all$Var1))
  plot_df$ct2 = factor(plot_df$ct2, levels = levels(net_names_all$Var1))
  #plot_df$ct1 = factor(plot_df$ct1, levels = rev(c("Stellate cells", "LSEC", "Endothelial cells\n(non-LSEC)",
  #                                                 "Kupffer cells", "cDCs", "Macrophages", "Cholangiocytes",
  #                                                 "pDCs", "ab-T cells", "Hepatocytes", "gd-T cells", 
  #                                                 "B cells", "Plasmablasts")))
  #plot_df$ct2 = factor(plot_df$ct2, levels = rev(c("Stellate cells", "LSEC", "Endothelial cells\n(non-LSEC)",
  #                                                 "Kupffer cells", "cDCs", "Macrophages", "Cholangiocytes",
  #                                                 "pDCs", "ab-T cells", "Hepatocytes", "gd-T cells", 
  #                                                 "B cells", "Plasmablasts")))
  pltcnts = ggplot(plot_df, aes(x = ct1, y = ct2, size = Freq, colour = Freq))+
    geom_point()+
    labs(x = "cell type", y = "cell type", title = n)+
    guides(colour = guide_legend(title = "# interactions", reverse = T), 
           size = guide_legend(title = "# interactions", reverse = T))+
    scale_colour_gradientn(colors = c("#ededed", "#deebf7", "#9ecae1", "#bcbddc", "#756bb1"), 
                           limits = c(0, 240))+
    scale_size_continuous(limits = c(0, 240))+
    theme_classic()+
    theme(aspect.ratio = 1,
          panel.background = element_rect(colour = "black"),
          axis.line = element_blank(),
          axis.text.x = element_text(angle = 90, hjust = 1, vjust = 0.4),
          axis.text = element_text(colour = "black"))
  cnts_list[[n]] = pltcnts
  tab_list[[n]] = dfct
}
cnts_list$legend = cowplot::get_legend(cnts_list$healthy)
cnts_list$healthy = cnts_list$healthy+theme(legend.position = "none")
cnts_list$embolised = cnts_list$embolised+theme(legend.position = "none")
cnts_list$regenerating = cnts_list$regenerating+theme(legend.position = "none")

pdf("figure_panels_rev1/fig_comm/suppFig_countsCond.pdf", height = 15, width = 15)
cnts_list[[1]]+cnts_list[[3]]+cnts_list[[2]]+cnts_list[[4]]+      patchwork::plot_layout(ncol = 2)
dev.off()

Heatmaps with difference in number of interactions vs healthy

Heatmaps by mid cell type

diff_cnt_l = list()
for(n in c("embolised", "regenerating")){
  dif_df = tab_list[[n]]-tab_list$healthy
  hcl = hclust(dist(dif_df), method = "ward.D2")
  plot_df = data.frame(dif_df)
  #plot_df$ct1 = factor(plot_df$ct1, levels = levels(plot_df$ct1)[hcl$order])
  #plot_df$ct2 = factor(plot_df$ct2, levels = levels(plot_df$ct2)[hcl$order])
  plot_df$ct1 = factor(plot_df$ct1, levels = levels(net_names_all$Var1))
  plot_df$ct2 = factor(plot_df$ct2, levels = levels(net_names_all$Var1))
  #plot_df$ct1 = factor(plot_df$ct1, levels = rev(c("Stellate cells", "LSEC", "Endothelial cells\n(non-LSEC)",
  #                                                 "Kupffer cells", "cDCs", "Macrophages", "Cholangiocytes",
  #                                                 "pDCs", "ab-T cells", "Hepatocytes", "gd-T cells", 
  #                                                 "B cells", "Plasmablasts")))
  #plot_df$ct2 = factor(plot_df$ct2, levels = rev(c("Stellate cells", "LSEC", "Endothelial cells\n(non-LSEC)",
  #                                                 "Kupffer cells", "cDCs", "Macrophages", "Cholangiocytes",
  #                                                 "pDCs", "ab-T cells", "Hepatocytes", "gd-T cells", 
  #                                                 "B cells", "Plasmablasts")))
  pltcnts = ggplot(plot_df[order(plot_df$Freq, decreasing = F),], 
                   aes(x = ct1, y = ct2, size = abs(Freq), colour = Freq))+
    geom_point()+
    labs(x = "cell type", y = "cell type", title = paste0(n, " - healthy"))+
    guides(colour = guide_legend(title = "change in\n# interactions", 
                                 reverse = T, override.aes = list(size = 4)), 
           size = guide_none())+
    scale_colour_gradientn(colors = c("#d7191c", "#fdae61", "#ededed", "#c2a5cf", "#7b3294"), 
                           limits = c(-110, 110))+
    scale_size_continuous(range = c(0.2, 5))+
    theme_classic()+
    theme(aspect.ratio = 1,
          panel.background = element_rect(colour = "black"),
          axis.line = element_blank(),
          axis.text.x = element_text(angle = 90, hjust = 1, vjust = 0.4),
          axis.text = element_text(colour = "black", size = 8))
  print(pltcnts)
  diff_cnt_l[[n]] = pltcnts
}

diff_cnt_l$legend = cowplot::get_legend(diff_cnt_l$embolised)
diff_cnt_l$embolised = diff_cnt_l$embolised+theme(legend.position = "none")
diff_cnt_l$regenerating = diff_cnt_l$regenerating+theme(legend.position = "none")

pdf("figure_panels_rev1/fig_comm/suppFig_countsDiff.pdf", height = 8, width = 15)
print(cowplot::plot_grid(plotlist = diff_cnt_l[c(2,1,3)], ncol = 3, rel_widths = c(1,1,0.3), align = "h"))
Warning: Graphs cannot be horizontally aligned unless the axis parameter is set. Placing graphs unaligned.
dev.off()
png 
  2 

Unique interactions from E and R

print(cowplot::plot_grid(plotlist = diff_cnt_l[c(2,1,3)], 
                         ncol = 3, rel_widths = c(1,1,0.3), align = "hv"))
Warning: Graphs cannot be vertically aligned unless the axis parameter is set. Placing graphs unaligned.
Warning: Graphs cannot be horizontally aligned unless the axis parameter is set. Placing graphs unaligned.

Functions to plot interactions

# number of new unique interactions
## i.e. this ligand-receptor pair was absent at least in healthy and always includes this ct
# get interactions that are not in healthy
inter_h = inter_df$healthy$id_cp_interaction
inter_reg_sub = inter_df$regenerating[!inter_df$regenerating$id_cp_interaction %in% inter_h,
                                      1:3]
inter_emb_sub = inter_df$embolised[!inter_df$embolised$id_cp_interaction %in% inter_h, 1:3]

pve_inter = rbind(inter_reg_sub, inter_emb_sub)
pve_inter$cond = c(rep("regenerating", nrow(inter_reg_sub)),
                   rep("embolised", nrow(inter_emb_sub)))
pve_inter$mid_ct1 = match_df[pve_inter$ct1,"ct_mid"]
pve_inter$mid_ct2 = match_df[pve_inter$ct2,"ct_mid"]

# list unique interactions (all ct)
ct_inter_l = list()
for(cond in unique(pve_inter$cond)){
  ct_inter_l[[cond]] = list()
  sub_pve_inter = pve_inter[pve_inter$cond==cond,]
  sub_pve_inter = sub_pve_inter[sub_pve_inter$ct1!=sub_pve_inter$ct2,]
  
  inter_u = unique(sub_pve_inter$id_cp_interaction)
  for(i in inter_u){
    idf = sub_pve_inter[sub_pve_inter$id_cp_interaction==i, c("ct1", "ct2")]
    tab_int_nu = table(idf$ct1, idf$ct2)
    
    if(nrow(tab_int_nu)==1){
      ct_inter_l[[cond]][[i]] = rownames(tab_int_nu)
    }
    if(ncol(tab_int_nu)==1){
      ct_inter_l[[cond]][[i]] = colnames(tab_int_nu)
    }
  }
  
}
ct_inter_l = reshape2::melt(ct_inter_l)
table(ct_inter_l$value, ct_inter_l$L1)
                            
                             embolised regenerating
  ab-T cells (stress)                3            0
  activated DCs                      0            1
  B cells                            1            1
  Dividing cDCs                      1            1
  Dividing endothelial cells         3            0
  EC non-LSEC                        2            0
  IgA+ Plasma cells                  0            1
  ILC3                               0            2
  Infiltrating NK cells              2            0
  LSEC (fenestr.)                    1            1
  LSEC (interferon)                  0            1
  LSEC (remodelling)                 0            3
  Lymphatic EC                       2            0
  Monocytes (TREM2+ CD9+)            1            1
  pDCs                               4            4
  Stellate cells                    10           17
  Treg                               1            0
# list unique interactions (mid ct)
ctmid_inter_l = list()
ctmid_inter_l_ct = list()
for(cond in unique(pve_inter$cond)){
  ctmid_inter_l[[cond]] = list()
  ctmid_inter_l_ct[[cond]] = list()
  sub_pve_inter = pve_inter[pve_inter$cond==cond,]
  sub_pve_inter = sub_pve_inter[sub_pve_inter$mid_ct1!=sub_pve_inter$mid_ct2,]
  
  inter_u = unique(sub_pve_inter$id_cp_interaction)
  for(i in inter_u){
    idf = sub_pve_inter[sub_pve_inter$id_cp_interaction==i, c("mid_ct1", "mid_ct2")]
    tab_int_nu = table(idf$mid_ct1, idf$mid_ct2)
    mid_ct1_ct = sub_pve_inter[sub_pve_inter$id_cp_interaction==i, "ct1"]
    mid_ct2_ct = sub_pve_inter[sub_pve_inter$id_cp_interaction==i, "ct2"]
    
    if(nrow(tab_int_nu)==1){
      ctmid_inter_l[[cond]][[i]] = rownames(tab_int_nu)
      ctmid_inter_l_ct[[cond]][[i]] = mid_ct1_ct
    }
    if(ncol(tab_int_nu)==1){
      ctmid_inter_l[[cond]][[i]] = colnames(tab_int_nu)
      ctmid_inter_l_ct[[cond]][[i]] = mid_ct2_ct
    }
  }
  
}
ctmid_inter_l = reshape2::melt(ctmid_inter_l)
ctmid_inter_l_ct = unique(reshape2::melt(ctmid_inter_l_ct))
ctmid_inter_l = merge(ctmid_inter_l, ctmid_inter_l_ct, by = c("L2", "L1"), 
                      all = T)[,c(3,1,2,4)]
table(ctmid_inter_l$value.x, ctmid_inter_l$L1)
                
                 embolised regenerating
  B cells                1            2
  Hepatocytes            9            6
  ILC                    2            2
  LSEC                   4            3
  Mesenchymal           10           17
  other ECs              8           10
  other Mono-Mac         2            3
  pDCs                   4            4
  T cells                3            0

Plot all

filtFuncU = function(x, intdf, mutthr = 0, expthr = 0.12, minct = 3){
  coldf = x[,1:8]
  #int_ct_p_t = paste0(intdf$value, intdf$L2)
  coldf$isMain1 = apply(coldf, 1, function(y) paste0(y[2], y[1]) %in% intdf)
  coldf$isMain2 = apply(coldf, 1, function(y) paste0(y[3], y[1]) %in% intdf)
  
  # swap if isMain2
  for(i in 1:nrow(coldf)){
    if(coldf[i,"isMain2"]){
      tmpct = coldf[i,"ct2"]
      tmplr = coldf[i,"lr2"]
      tmpma = coldf[i,"isMain2"]
      
      coldf[i,"ct2"] = coldf[i,"ct1"]
      coldf[i,"lr2"] = coldf[i,"lr1"]
      coldf[i,"isMain2"] = coldf[i,"isMain1"]
      
      coldf[i,"ct1"] = tmpct
      coldf[i,"lr1"] = tmplr
      coldf[i,"isMain1"] = tmpma
    }
  }

  # interaction names
  coldf$intlr = paste0(coldf$lr1, " -\n ", coldf$lr2)
  coldf = unique(coldf[,c(2,3,11,6:10)])
  # interaction frequency
  nint = table(coldf$intlr)
  # expression and interaction filtering
  coldf = coldf[apply(coldf[,4:6], 1, function(x) any(x>=expthr)) & 
                  (coldf$intlr %in% names(nint)[nint>1] | 
                     apply(coldf[,4:6], 1, function(x) any(x>=expthr*8))),]
  # reshaping for plot
  coldf = data.table::rbindlist(list(reshape2::melt(coldf[,c(3,1,4:7)]), 
                                     reshape2::melt(coldf[,c(3,2,4:6, 8)])), use.names = F)
  coldf$variable = unlist(lapply(strsplit(as.character(coldf$variable), "_"), 
                                 function(x) x[1]))
  coldf$variable = factor(coldf$variable, levels = c("healthy","regenerating", "embolised"))
  coldf = coldf[order(coldf$value, decreasing = T),]
  coldf = coldf[!duplicated(coldf[,1:4]),]
  coldf$ct1 = gsub("Endothelial cells", "EC", coldf$ct1)
  coldf$intlr = gsub("receptor", "rec", coldf$intlr)
  coldf$intlr = gsub("complex", "comp", coldf$intlr)
  nct = table(coldf$ct1)
  coldf = coldf[coldf$ct1 %in% names(nct)[nct>=minct*3],]
  nint = table(coldf$intlr)
  coldf = coldf[coldf$intlr %in% names(nint)[nint>3],]
  
  # confirm that all interactions have at least one TRUE
  ntrue = tapply(coldf$isMain1, coldf$intlr, sum)
  coldf = coldf[coldf$intlr %in% names(ntrue)[ntrue>0]]
  
  # formatting
  coldf = coldf[order(coldf$isMain1, coldf$intlr, -coldf$value, decreasing = T),]
  coldf$ct1 = factor(coldf$ct1, levels = rev(unique(coldf$ct1)))
  coldf$intlr = factor(coldf$intlr, levels = rev(unique(coldf$intlr)))
  coldf = coldf[order(coldf$isMain1, decreasing = F),]
  
  return(coldf)
}

pltFuncU = function(x){
  plt = ggplot(x, aes(y = ct1, x = variable, fill = value, colour = isMain1))+
    facet_grid(intlr~., scales = "free_y", space = "free_y")+
    geom_tile(size = 0.4)+
    scale_x_discrete(expand = c(0,0))+
    scale_fill_gradientn(colors = gradexpcol)+
    scale_colour_manual(values = c("white", "black"))+
    guides(fill = guide_colourbar(barheight = unit(0.4, "cm")),
           colour = guide_none())+
    labs(x = "Condition", y = "Cell type", fill = "mean exp")+
    theme_classic()+
    theme(axis.text.y = element_text(colour = "black", size = 7, 
                                     angle = 0, hjust = 1, vjust = 0.5),
          axis.text.x = element_text(colour = "black", size = 6.5, 
                                     angle = 35, hjust=1, vjust=1),
          axis.title = element_text(size = 7),
          axis.line = element_blank(),
          legend.position = "bottom",
          legend.title = element_text(size = 7),
          legend.box.margin = margin(0,0,0,0),
          legend.text = element_text(size = 6),
          strip.text.y = element_text(angle = 0, size = 7, margin = margin(0,0,3,0), 
                                      hjust = 0.5, vjust = 0.5, face = "bold"),
          strip.background = element_blank())
  return(plt)
}

Plot one by one

plot_df = filtFuncU(her_allint_f[her_allint_f$id_cp_interaction %in% ct_inter_l$L2[!grepl("stress", ct_inter_l$value)],],
                    intdf = paste0(ct_inter_l$value, ct_inter_l$L2), 
                    expthr = 0.2, minct = 1)
Using intlr, ct1, isMain1 as id variables
Using intlr, ct2, isMain2 as id variables
imm_plt = pltFuncU(plot_df)
pdf("figure_panels_rev1/fig_comm/mainFig_InteractUnique.pdf", 
    height = 20, width = 2.8)
print(imm_plt)
dev.off()
null device 
          1 
plot_df = filtFuncU(her_allint_f[her_allint_f$id_cp_interaction %in% ctmid_inter_l$L2[!grepl("stress", ctmid_inter_l$value.y)],],
                   intdf = paste0(ctmid_inter_l$value.y, ctmid_inter_l$L2), 
                   expthr = 0.2, minct = 3)
Using intlr, ct1, isMain1 as id variables
Using intlr, ct2, isMain2 as id variables
imm_plt = pltFuncU(plot_df)
pdf("figure_panels_rev1/fig_comm/mainFig_InteractUnique_mid.pdf", 
    height = 32, width = 2.8)
print(imm_plt)
dev.off()
null device 
          1 

Plot one by one, all in H vs PVE network

plot_df = filtFuncU(her_allint_f[her_allint_f$id_cp_interaction %in% ct_inter_l$L2[!grepl("stress", ct_inter_l$value)],],
                    intdf = paste0(ct_inter_l$value, ct_inter_l$L2), 
                    expthr = 0.2, minct = 3)
Using intlr, ct1, isMain1 as id variables
Using intlr, ct2, isMain2 as id variables
folder = "figure_panels_rev1/fig_comm/heatmaps_interact_indiv/"
for(i in 1:length(unique(plot_df$intlr))){
  iii = unique(plot_df$intlr)[i]
  sub_plot_df = plot_df[plot_df$intlr==iii,]
  sub_plot_df = sub_plot_df[order(sub_plot_df$isMain1, sub_plot_df$value, decreasing = T),]
  sub_plot_df$ct1 = factor(sub_plot_df$ct1, levels = rev(unique(sub_plot_df$ct1)))
  sub_plot_df = sub_plot_df[order(sub_plot_df$isMain1, decreasing = F),]
  
  pdf(paste0(folder, "mainFig_InteractUnique_", i, ".pdf"), height = 3, width = 4)
  print(pltFuncU(sub_plot_df))
  dev.off()
}

plot_df = filtFuncU(her_allint_f[her_allint_f$id_cp_interaction %in% ctmid_inter_l$L2[!grepl("stress", ctmid_inter_l$value.y)],],
                   intdf = paste0(ctmid_inter_l$value.y, ctmid_inter_l$L2), 
                   expthr = 0.2, minct = 3)
Using intlr, ct1, isMain1 as id variables
Using intlr, ct2, isMain2 as id variables
folder = "figure_panels_rev1/fig_comm/heatmaps_interact_indiv/"
for(i in 1:length(unique(plot_df$intlr))){
  iii = unique(plot_df$intlr)[i]
  sub_plot_df = plot_df[plot_df$intlr==iii,]
  sub_plot_df = sub_plot_df[order(sub_plot_df$isMain1, sub_plot_df$value, decreasing = T),]
  sub_plot_df$ct1 = factor(sub_plot_df$ct1, levels = rev(unique(sub_plot_df$ct1)))
  sub_plot_df = sub_plot_df[order(sub_plot_df$isMain1, decreasing = F),]
  
  pdf(paste0(folder, "mainFig_InteractUnique_mid_", i, ".pdf"), height = 3, width = 2.8)
  print(pltFuncU(sub_plot_df))
  dev.off()
}

Plot changes in number of interactions per condition - mid resolution

plot_df = filtFunc(her_allint_f[her_allint_f$id_cp_interaction %in% unique(edge_min$id_cp_interaction),],
                   expthr = 0.15, minct = 2)
Using intlr, ct1 as id variables
Using intlr, ct2 as id variables

Panels cirrhosis

UMAP Immune cells

UMAP Mono/Mac cells

m_df = readRDS(file = "results/cirrhosis/umap_m_df.RDS")

cols = MetBrewer::met.brewer("Klimt", length(unique(m_df$all_annot)))
names(cols) = unique(m_df$all_annot)

m_df = m_df[sample(1:nrow(m_df), nrow(m_df), replace = F),]
plt = ggplot()+
  geom_point(aes(x = UMAP_1, y = UMAP_2, colour = all_annot), 
             m_df, size = 0.2)+
  guides(colour = guide_legend(override.aes = list(size = 3)))+
  scale_colour_manual(values = cols[order(names(cols))])+
  theme_void()+
  theme(aspect.ratio = 1,
        legend.text = element_text(size = 6),
        legend.key.size = unit(0.4, "cm"),
        legend.title = element_blank())

pdf("figure_panels_rev1/fig_cir/all_mono_umap.pdf", height = 2.2, width = 4.2)
print(plt)
dev.off()

UMAP T/NK cells

t_df = readRDS(file = "results/cirrhosis/umap_t_df.RDS")

cols = MetBrewer::met.brewer("Juarez", length(unique(t_df$all_annot)))
names(cols) = unique(t_df$all_annot)

t_df = t_df[sample(1:nrow(t_df), nrow(t_df), replace = F),]
plt = ggplot()+
  geom_point(aes(x = UMAP_1, y = UMAP_2, colour = all_annot), 
             t_df, size = 0.2)+
  guides(colour = guide_legend(override.aes = list(size = 3)))+
  scale_colour_manual(values = cols[order(names(cols))])+
  theme_void()+
  theme(aspect.ratio = 1,
        legend.text = element_text(size = 6),
        legend.key.size = unit(0.375, "cm"),
        legend.title = element_blank())

pdf("figure_panels_rev1/fig_cir/all_tnk_umap.pdf", height = 2.2, width = 4.2)
print(plt)
dev.off()

Markers myeloid cells

mat_m = readRDS(file = "results/cirrhosis/mat_myeloid_markers.RDS")

cols_pal = colorRampPalette(rev(brewer.pal(n = 9, name = "RdBu")))(100)

pdf("figure_panels_rev1/fig_cir/heat_mk_mye.pdf", height = 2.2, width = 6.3)
pheatmap::pheatmap(mat_m, clustering_method = "ward.D", color = cols_pal,
                   treeheight_col = 0, treeheight_row = 20, fontsize = 6.3)
dev.off()

Markers lymphoid cells

mat_l = readRDS("results/cirrhosis/mat_lymphoid_markers.RDS")

cols_pal = colorRampPalette(rev(brewer.pal(n = 9, name = "RdBu")))(100)

pdf("figure_panels_rev1/fig_cir/heat_mk_lym.pdf", height = 2.2, width = 6.3)
pheatmap::pheatmap(mat_l, clustering_method = "ward.D", color = cols_pal,
                   treeheight_col = 0, treeheight_row = 20, fontsize = 6.3)
dev.off()

Proportions immune cells

imm_props = readRDS(file = "results/cirrhosis/imm_props_dat.RDS")
imm_pvals = readRDS("results/cirrhosis/imm_props_pval.RDS")

plt = ggplot(imm_props, aes(x = Condition, y = Freq, group = Condition, colour = Condition))+
  facet_wrap(~Var1, scales = "free")+
  geom_jitter(position = position_jitterdodge(jitter.width = 0.3, dodge.width = 1))+
  stat_summary(fun.data = mean_se, position = position_dodge(width = 1), 
               alpha = 0.35, colour = "black")+
  theme_bw()+
  theme(legend.position = "none")


colnames(imm_pvals)[1] = "embolized"

imm_props$Condition[imm_props$Condition=="embolised"] = "embolized"
imm_props$Condition = factor(imm_props$Condition, 
                             levels = c("healthy", "regenerating", "embolized"))

pval_pos = imm_props %>%
  group_by(Condition, Var1) %>%
  summarise_at(vars("Freq"), mean)
pval_pos$posy = pval_pos$Freq*1.02
pval_pos$posx = as.numeric(pval_pos$Condition)+0.3
pval_pos = pval_pos[pval_pos$Condition!="healthy",]
pval_pos$pval = diag(as.matrix(imm_pvals[pval_pos$Var1,as.character(pval_pos$Condition)]))
pval_pos$issig = ifelse(pval_pos$pval<=0.05, "*", "")

plt = ggplot()+
  facet_wrap(~Var1, scales = "free")+
  geom_jitter(data = imm_props, mapping = aes(x = Condition, y = Freq, 
                                              group = Condition, colour = Condition),
              position = position_jitterdodge(jitter.width = 0.3, dodge.width = 1), size = 0.5)+
  stat_summary(data = imm_props, mapping = aes(x = Condition, y = Freq, 
                                              group = Condition, colour = Condition),
               fun.data = mean_se, position = position_dodge(width = 1), 
               alpha = 0.6, colour = "black", size = 0.25)+
  geom_text(data = pval_pos, mapping = aes(x = posx, y = posy, label = issig), size = 4)+
  scale_colour_manual(values = colcond, drop = T, limits = names(colcond)[c(1,2,4)])+
  scale_x_discrete(labels = c("H", "R", "E"))+
  labs(y = "proportion % (immune)")+
  theme_bw()+
  theme(legend.position = "none",
        axis.title = element_text(size = 6, colour = "black"),
        axis.text.x = element_text(size = 6, colour = "black"),
        axis.text.y = element_text(size = 6, colour = "black"),
        strip.text = element_text(size = 6),
        strip.background = element_rect(fill = "white"),
        panel.grid.minor = element_blank(),
        panel.grid.major.x = element_blank(),
        panel.grid.major.y = element_line(size = 0.3, colour = "grey70"))

#pdf("figure_panels_rev1/fig_cir/immune_all_prop.pdf", height = 7.5, width = 11.5)
print(plt)
#dev.off()

pdf("figure_panels_rev1/fig_cir/immune_all_prop_resized.pdf", height = 5.5, width = 7)
print(plt)
dev.off()

Proportions endothelial cells

plt = ggplot()+
  facet_wrap(~Var1, scales = "free")+
  geom_jitter(data = imm_props, mapping = aes(x = Condition, y = Freq, 
                                              group = Condition, colour = Condition),
              position = position_jitterdodge(jitter.width = 0.3, dodge.width = 1), size = 0.5)+
  stat_summary(data = imm_props, mapping = aes(x = Condition, y = Freq, 
                                              group = Condition, colour = Condition),
               fun.data = mean_se, position = position_dodge(width = 1), 
               alpha = 0.6, colour = "black", size = 0.25)+
  geom_text(data = pval_pos, mapping = aes(x = posx, y = posy, label = issig), size = 4)+
  scale_colour_manual(values = colcond, drop = T, limits = names(colcond)[c(1,2,4)])+
  scale_x_discrete(labels = c("H", "R", "E"))+
  labs(y = "proportion % (immune)")+
  theme_bw()+
  theme(legend.position = "none",
        axis.title = element_text(size = 6, colour = "black"),
        axis.text.x = element_text(size = 6, colour = "black"),
        axis.text.y = element_text(size = 6, colour = "black"),
        strip.text = element_text(size = 6),
        strip.background = element_rect(fill = "white"),
        panel.grid.minor = element_blank(),
        panel.grid.major.x = element_blank(),
        panel.grid.major.y = element_line(size = 0.3, colour = "grey70"))

#pdf("figure_panels_rev1/fig_cir/immune_all_prop.pdf", height = 7.5, width = 11.5)
print(plt)
#dev.off()

pdf("figure_panels_rev1/fig_cir/immune_all_prop_resized.pdf", height = 5.5, width = 7)
print(plt)
dev.off()
png 
  2 

MP signatures

mp_sig_df = readRDS(file = "results/cirrhosis/mono_cirr_ct_signatures.RDS")

plot_df = reshape2::melt(mp_sig_df)
plot_df$Condition[plot_df$Condition=="embolised"] = "embolized"
plot_df$Condition = factor(plot_df$Condition, 
                           levels = c("healthy","regenerating","embolized"))
sub_plot_df = plot_df[plot_df$variable %in% c("cirr_ct_MPs_4","cirr_ct_MPs_5"),]
sub_plot_df$variable = gsub("cirr_ct_MPs_4", "SAMac (1)", sub_plot_df$variable)
sub_plot_df$variable = gsub("cirr_ct_MPs_5", "SAMac (2)", sub_plot_df$variable)

plt = ggplot(sub_plot_df, aes(x = mono_annot, y = value, fill = Condition))+
  facet_grid(variable~mono_annot, scales = "free")+
  geom_hline(yintercept = 0, linetype = "dashed", size = 0.3)+
  geom_violin(scale = "count")+
  scale_fill_manual(values = colcond, drop = T, limits = names(colcond)[c(1,2,4)])+
  theme_classic()+
  theme(axis.text.x = element_blank(),
        axis.title.x = element_blank(),
        axis.ticks.x = element_blank(),
        axis.text.y = element_text(size = 6, colour = "black"),
        axis.title.y = element_text(size = 6.5),
        strip.text = element_text(size = 7),
        panel.border = element_rect(colour = "black", fill = NA),
        axis.line = element_blank(),
        legend.position = c(0.048, 0.865),
        legend.background = element_blank(),
        legend.key.size = unit(0.3, "cm"),
        legend.text = element_text(size = 6.5),
        legend.title = element_text(size = 7))

pdf("figure_panels_rev1/fig_cir/mp_sig_vio.pdf", height = 3, width = 10.35)
print(plt)
dev.off()

Endothelial signatures

mp_sig_df = readRDS(file = "results/cirrhosis/mono_cirr_ct_signatures.RDS")

plot_df = reshape2::melt(mp_sig_df)
Using Condition, mono_annot as id variables
plot_df$Condition[plot_df$Condition=="embolised"] = "embolized"
plot_df$Condition = factor(plot_df$Condition, 
                           levels = c("healthy","regenerating","embolized"))
sub_plot_df = plot_df[plot_df$variable %in% c("cirr_ct_MPs_4","cirr_ct_MPs_5"),]
sub_plot_df$variable = gsub("cirr_ct_MPs_4", "SAMac (1)", sub_plot_df$variable)
sub_plot_df$variable = gsub("cirr_ct_MPs_5", "SAMac (2)", sub_plot_df$variable)

plt = ggplot(sub_plot_df, aes(x = mono_annot, y = value, fill = Condition))+
  facet_grid(variable~mono_annot, scales = "free")+
  geom_hline(yintercept = 0, linetype = "dashed", size = 0.3)+
  geom_violin(scale = "count")+
  scale_fill_manual(values = colcond, drop = T, limits = names(colcond)[c(1,2,4)])+
  theme_classic()+
  theme(axis.text.x = element_blank(),
        axis.title.x = element_blank(),
        axis.ticks.x = element_blank(),
        axis.text.y = element_text(size = 6, colour = "black"),
        axis.title.y = element_text(size = 6.5),
        strip.text = element_text(size = 7),
        panel.border = element_rect(colour = "black", fill = NA),
        axis.line = element_blank(),
        legend.position = c(0.048, 0.865),
        legend.background = element_blank(),
        legend.key.size = unit(0.3, "cm"),
        legend.text = element_text(size = 6.5),
        legend.title = element_text(size = 7))

pdf("figure_panels_rev1/fig_cir/mp_sig_vio.pdf", height = 3, width = 10.35)
print(plt)
dev.off()
null device 
          1 

Hepatocyte signatures

end_sig_df = readRDS(file = "results/cirrhosis/endo_cirr_ct_signatures.RDS")

plot_df = reshape2::melt(end_sig_df)
Using Condition, endo_simp as id variables
plot_df$Condition[plot_df$Condition=="embolised"] = "embolized"
plot_df$Condition[plot_df$Condition=="embolised"] = "embolized"
plot_df$Condition = factor(plot_df$Condition, 
                           levels = c("healthy","regenerating","embolized"))
sub_plot_df = plot_df[plot_df$variable %in% c("cirr_ct_Endothelia_6","cirr_ct_Endothelia_7"),]
sub_plot_df$variable = gsub("cirr_ct_Endothelia_6", 
                            "SAEndothelial (1)", sub_plot_df$variable)
sub_plot_df$variable = gsub("cirr_ct_Endothelia_7", "SAEndothelial (2)",
                            sub_plot_df$variable)

plt = ggplot(sub_plot_df, aes(x = endo_simp, y = value, fill = Condition))+
  facet_grid(variable~endo_simp, scales = "free")+
  geom_hline(yintercept = 0, linetype = "dashed", size = 0.3)+
  geom_violin(scale = "count")+
  scale_fill_manual(values = colcond, drop = T, limits = names(colcond)[c(1,2,4)])+
  theme_classic()+
  theme(axis.text.x = element_blank(),
        axis.title.x = element_blank(),
        axis.ticks.x = element_blank(),
        axis.text.y = element_text(size = 6, colour = "black"),
        axis.title.y = element_text(size = 6.5),
        strip.text = element_text(size = 7),
        panel.border = element_rect(colour = "black", fill = NA),
        axis.line = element_blank(),
        legend.position = "bottom",
        legend.background = element_blank(),
        legend.margin = margin(0,0,0,0),
        legend.key.size = unit(0.3, "cm"),
        legend.text = element_text(size = 6.5),
        legend.title = element_text(size = 7))

pdf("figure_panels_rev1/fig_cir/endo_sig_vio.pdf", height = 2.8, width = 11)
print(plt)
dev.off()
null device 
          1 
LS0tCnRpdGxlOiAiRmlndXJlIFBsb3R0aW5nIFJldjEiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCk5vdGVib29rIHRvIG1ha2UgdGhlIHBhbmVscyBmb3IgdGhlIHBhcGVyIGZpZ3VyZXMgYWZ0ZXIgcmV2aXNpb24KCiMgR2VuZXJhbCBTZXR1cApTZXR1cCBjaHVuawoKYGBge3IsIHNldHVwLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoZmlnLndpZHRoID0gOCkKa25pdHI6Om9wdHNfa25pdCRzZXQocm9vdC5kaXIgPSBub3JtYWxpemVQYXRoKCIuLiIpKQprbml0cjo6b3B0c19rbml0JGdldCgicm9vdC5kaXIiKQpgYGAKCkxvYWQgbGlicmFyaWVzCgpgYGB7cn0KbGlicmFyeShkcGx5cikKbGlicmFyeShTZXVyYXQpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShnZ3JlcGVsKQpsaWJyYXJ5KGdncmlkZ2VzKQpsaWJyYXJ5KHBoZWF0bWFwKQpsaWJyYXJ5KFJDb2xvckJyZXdlcikKbGlicmFyeShNZXRCcmV3ZXIpCmBgYAoKRGVmaW5lIHBsb3QgdGhlbWUocykKCmBgYHtyfQp0aF9nZW4gPSB0aGVtZShheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDcsIGNvbG91ciA9ICJibGFjayIpLAogICAgICAgICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA4LCBjb2xvdXIgPSAiYmxhY2siKSwKICAgICAgICAgICAgICAgYXhpcy5saW5lID0gZWxlbWVudF9saW5lKGNvbG91ciA9ICJibGFjayIpLAogICAgICAgICAgICAgICBwbG90LmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICBwYW5lbC5ncmlkID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICBsZWdlbmQuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgICAgICAgIGxlZ2VuZC5rZXkuc2l6ZSA9IHVuaXQoMC4zNSwgImNtIiksCiAgICAgICAgICAgICAgIGxlZ2VuZC5rZXkgPSBlbGVtZW50X2JsYW5rKCksIGxlZ2VuZC5zcGFjaW5nID0gdW5pdCgwLjcsICJjbSIpLAogICAgICAgICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gOSksCiAgICAgICAgICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLAogICAgICAgICAgICAgICBsZWdlbmQuYm94Lm1hcmdpbiA9IG1hcmdpbigwLjEsMC4xLDAuMSwwLjEpLAogICAgICAgICAgICAgICBsZWdlbmQuYm94LnNwYWNpbmcgPSB1bml0KDAuNSwiY20iKSkKcG9pbnRzaXplID0gMC4zCnRoZW1lX3NldCh0aF9nZW4pCmBgYAoKVXNlZnVsIGZ1bmN0aW9ucwoKYGBge3J9CmJyZWFrU3RyID0gZnVuY3Rpb24ocywgbiA9IDIwKSB7cmV0dXJuKGdzdWIocGFzdGUwKCcoLnsxLCcsYXMuY2hhcmFjdGVyKG4pLCd9KShcXHN8JCknKSwgJ1xcMVxuJywgcykpfQoKZ2V0VG9wVGVybXMgPSBmdW5jdGlvbihnb2RmLCB0b3B0ID0gMTAwLCBuY2wgPSA1LCBudCA9IDIpewogIHRvcHQgPSBpZihucm93KGdvZGYpPHRvcHQpIG5yb3coZ29kZikgZWxzZSB0b3B0CiAgaWYobnJvdyhnb2RmKTxuY2wpIHJldHVybihnb2RmKQogIGRmID0gZ29kZlsxOnRvcHQsXQogIGdlbmVzID0gc2FwcGx5KGRmJGdlbmVJRCwgZnVuY3Rpb24oeCkgc3Ryc3BsaXQoeCwgIi8iKSkKICByZXNtYXQgPSBtYXRyaXgoMCwgbGVuZ3RoKGdlbmVzKSwgbGVuZ3RoKGdlbmVzKSkKICBmb3IoaSBpbiAxOmxlbmd0aChnZW5lcykpewogICAgZm9yKGogaW4gMTpsZW5ndGgoZ2VuZXMpKXsKICAgICAgcmVzbWF0W2ksal0gPSBsZW5ndGgoaW50ZXJzZWN0KGdlbmVzW1tpXV0sIGdlbmVzW1tqXV0pKS9sZW5ndGgoZ2VuZXNbW2ldXSkKICAgIH0KICB9CiAgY2wgPSBoY2x1c3QoZGlzdChyZXNtYXQpLCBtZXRob2QgPSAid2FyZC5EMiIpCiAgY2wgPSBjdXRyZWUoY2wsIG5jbCkKICByZXNfZGYgPSBkYXRhLmZyYW1lKCJEZXNjcmlwdGlvbiIgPSBkZiREZXNjcmlwdGlvbiwgInF2YWx1ZSIgPSBkZiRxdmFsdWUsIGNsLCAKICAgICAgICAgICAgICAgICAgICAgICJnZW5lSUQiID0gdW5saXN0KGRmJGdlbmVJRCksIHN0cmluZ3NBc0ZhY3RvcnMgPSBGKQogIHJlc19kZiA9IHJlc19kZltvcmRlcihyZXNfZGYkcXZhbHVlLCBkZWNyZWFzaW5nID0gRiksXQogIHRvcHRlcm1zID0gdW5saXN0KHRhcHBseShyZXNfZGYkRGVzY3JpcHRpb24sIHJlc19kZiRjbCwgZnVuY3Rpb24oeCkgeFsxOm50XSkpCiAgcmVzX2RmID0gcmVzX2RmW3Jlc19kZiREZXNjcmlwdGlvbiAlaW4lIHRvcHRlcm1zLF0KICAKICByZXR1cm4ocmVzX2RmKQp9CgpnZXRUb3BUZXJtc1BhaXJlZCA9IGZ1bmN0aW9uKGdvZGYsIGdlbmVzY29sID0gImdlbmVzX2FsbCIsIG5jbCA9IDUsIG50ID0gMil7CiAgaWYobnJvdyhnb2RmKTxuY2wpIHJldHVybihnb2RmKQogIGdlbmVzID0gc2FwcGx5KGdvZGZbLGdlbmVzY29sXSwgZnVuY3Rpb24oeCkgc3Ryc3BsaXQoeCwgIi8iKSkKICByZXNtYXQgPSBtYXRyaXgoMCwgbGVuZ3RoKGdlbmVzKSwgbGVuZ3RoKGdlbmVzKSkKICBmb3IoaSBpbiAxOmxlbmd0aChnZW5lcykpewogICAgZm9yKGogaW4gMTpsZW5ndGgoZ2VuZXMpKXsKICAgICAgcmVzbWF0W2ksal0gPSBsZW5ndGgoaW50ZXJzZWN0KGdlbmVzW1tpXV0sIGdlbmVzW1tqXV0pKS9sZW5ndGgoZ2VuZXNbW2ldXSkKICAgIH0KICB9CiAgY2wgPSBoY2x1c3QoZGlzdChyZXNtYXQpLCBtZXRob2QgPSAid2FyZC5EMiIpCiAgY2wgPSBjdXRyZWUoY2wsIG5jbCkKICByZXNfZGYgPSBkYXRhLmZyYW1lKCJEZXNjcmlwdGlvbiIgPSBnb2RmJERlc2NyaXB0aW9uLCAicXZhbF9lbWJvbGl6ZWQiID0gZ29kZiRxdmFsX2VtYm9saXplZCwgCiAgICAgICAgICAgICAgICAgICAgICAicXZhbF9yZWdlbmVyYXRpbmciID0gZ29kZiRxdmFsX3JlZ2VuZXJhdGluZywgCiAgICAgICAgICAgICAgICAgICAgICAiZ2VuZXNfZW1ib2xpemVkIiA9IHVubGlzdChnb2RmJGdlbmVzX2VtYm9saXplZCksIAogICAgICAgICAgICAgICAgICAgICAgImdlbmVzX3JlZ2VuZXJhdGluZyIgPSB1bmxpc3QoZ29kZiRnZW5lc19yZWdlbmVyYXRpbmcpLAogICAgICAgICAgICAgICAgICAgICAgY2wsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGKQogIHJlc19kZiRxdmFsX21heCA9IGFwcGx5KHJlc19kZlssYygicXZhbF9lbWJvbGl6ZWQiLCJxdmFsX3JlZ2VuZXJhdGluZyIpXSwgMSwgZnVuY3Rpb24oeCkgbWluKHgpKQogIHJlc19kZiA9IHJlc19kZltvcmRlcihyZXNfZGYkcXZhbF9tYXgsIGRlY3JlYXNpbmcgPSBGKSxdCiAgdG9wdGVybXMgPSB1bmxpc3QodGFwcGx5KHJlc19kZiREZXNjcmlwdGlvbiwgcmVzX2RmJGNsLCBmdW5jdGlvbih4KSB4WzE6bnRdKSkKICByZXNfZGYgPSByZXNfZGZbcmVzX2RmJERlc2NyaXB0aW9uICVpbiUgdG9wdGVybXMsXQogIAogIHJldHVybihyZXNfZGYpCn0KCnJwZmlsdGVyID0gZnVuY3Rpb24oeCl7CiAgcmV0dXJuKCFncmVwbCgiXlJQTCIsIHgkZ2VuZUlEKSAmICFncmVwbCgiXlJQUyIsIHgkZ2VuZUlEKSAmIAogICAgICAgICAgICFncmVwbCgiL1JQTCIsIHgkZ2VuZUlELCBmaXhlZCA9IFQpICYgIWdyZXBsKCIvUlBTIiwgeCRnZW5lSUQsIGZpeGVkID0gVCkpCn0KYGBgCgpDb2xvdXIgcGFsZXR0ZXMKCmBgYHtyfQpjb2xzbWFqb3IgPSBjKCJDaG9sYW5naW9jeXRlcyIgPSAiYmlzcXVlMiIsICJFbmRvdGhlbGlhbCIgPSAiYXF1YW1hcmluZTQiLCAgCiAgICAgICAgICAgICAgIkhlcGF0b2N5dGVzIiA9ICJ0b21hdG8zIiwgIkltbXVuZSIgPSAic2t5Ymx1ZSIsIAogICAgICAgICAgICAgICJNZXNlbmNoeW1hbCIgPSAic2FuZHlicm93biIsICJEb3VibGV0cyIgPSAiZ3JleTkwIikKY29sY29uZCA9IGMoImhlYWx0aHkiID0gIm9yYW5nZSIsICJyZWdlbmVyYXRpbmciID0gInNhbG1vbiIsIAogICAgICAgICAgICAiZW1ib2xpc2VkIiA9ICJkYXJrcmVkIiwgImVtYm9saXplZCIgPSAiZGFya3JlZCIpCmNvbGRvbiA9IGMoInNjX0gxIiA9ICJwbHVtNCIsICJzY19IMiIgPSAic2FsbW9uNCIsICJzY19IMyIgPSAibGlnaHRzYWxtb24zIikKY29sZG9uYWxsID0gYygic2NfSDEiID0gInBsdW00IiwgInNjX0gyIiA9ICJzYWxtb240IiwgInNjX0gzIiA9ICJsaWdodHNhbG1vbjMiLCAKICAgICAgICAgICAgICAic2NfRTEiID0gImRhcmtvcmFuZ2UzIiwgInNjX1IxIiA9ICJkYXJrb3JhbmdlMyIsICJzY19FMiIgPSAiZ29sZGVucm9kMyIsIAogICAgICAgICAgICAgICJzY19SMiIgPSAiZ29sZGVucm9kMyIsICAic2NfRTMiID0gIm1lZGl1bW9yY2hpZCIsICJzY19SMyIgPSAibWVkaXVtb3JjaGlkIiwgCiAgICAgICAgICAgICAgInNjX0U0IiA9ICJwbHVtMiIsICJzY19SNCIgPSAicGx1bTIiLCAic2NfRTUiID0gInBhbGV2aW9sZXRyZWQzIiwgCiAgICAgICAgICAgICAgInNjX1I1IiA9ICJwYWxldmlvbGV0cmVkMyIsICJzY19FNiIgPSAicGVhY2hwdWZmMiIsICJzY19SNiIgPSAicGVhY2hwdWZmMiIsCiAgICAgICAgICAgICAgInNjX0UxL3NjX1IxIiA9ICJkYXJrb3JhbmdlMyIsICJzY19FMi9zY19SMiIgPSAiZ29sZGVucm9kMyIsIAogICAgICAgICAgICAgICJzY19FMy9zY19SMyIgPSAibWVkaXVtb3JjaGlkIiwgInNjX0U0L3NjX1I0IiA9ICJwbHVtMiIsIAogICAgICAgICAgICAgICJzY19FNS9zY19SNSIgPSAicGFsZXZpb2xldHJlZDMiLCAic2NfRTYvc2NfUjYiID0gInBlYWNocHVmZjIiKQoKY29sc2FsbGN0ID0gYygiQ2hvbGFuZ2lvY3l0ZXMiID0gImJpc3F1ZTIiLCAiSGVwYXRvY3l0ZXMiID0gInRvbWF0bzMiLCAiU3RlbGxhdGUgY2VsbHMiID0gInNhbmR5YnJvd24iLCAKICAgICAgICAgICAgICAiRG91YmxldHMiID0gImdyZXk5MCIsICJMU0VDIHBlcmljZW50cmFsIiA9ICJhcXVhbWFyaW5lNCIsICJMU0VDIHBlcmlwb3J0YWwiID0gImFxdWFtYXJpbmUyIiwgCiAgICAgICAgICAgICAgIkVuZG90aGVsaWFsIGNlbGxzIChub24tTFNFQykiID0gImZvcmVzdGdyZWVuIiwgIlBsYXNtYWJsYXN0cyIgPSAiZGFya29yY2hpZDQiLAogICAgICAgICAgICAgICJLdXBmZmVyIGNlbGxzIiA9ICJza3libHVlMSIsICJhYi1UIGNlbGxzIiA9ICJsaWdodHNreWJsdWUzIiwgImdkLVQgY2VsbHMiID0gImNvcm5mbG93ZXJibHVlIiwKICAgICAgICAgICAgICAiQiBjZWxscyIgPSAiZGFya29yY2hpZDEiLCAiY0RDcyIgPSAiZGVlcHNreWJsdWUxIiwgInBEQ3MiID0gInJveWFsYmx1ZTMiLCAKICAgICAgICAgICAgICAiTWFjcm9waGFnZXMiID0gInN0ZWVsYmx1ZTMiLCAiRGl2aWRpbmcgY2VsbHMiID0gImdyZXkzNSIsICJMU0VDIiA9ICJhcXVhbWFyaW5lMyIpCmNvbHN1YiA9IGMoInJvc3licm93bjQiLCJ0aGlzdGxlNCIsInRoaXN0bGUzIiwiYXF1YW1hcmluZTQiLCJhcXVhbWFyaW5lMyIsCiAgICAgICAgICAgImZvcmVzdGdyZWVuIiwidG9tYXRvNCIsInRvbWF0bzMiLCJkYXJrc2FsbW9uIiwic2t5Ymx1ZSIsCiAgICAgICAgICAgImNhZGV0Ymx1ZSIsInNhbmR5YnJvd24iLCJwYWxlZ29sZGVucm9kIikKY29sc21pZGN0ID0gYygiQ2hvbGFuZ2lvY3l0ZXMiID0gImJpc3F1ZTIiLCAiSGVwYXRvY3l0ZXMiID0gInRvbWF0bzMiLCAKICAgICAgICAgICAgICAiTWVzZW5jaHltYWwiID0gInNhbmR5YnJvd24iLCAicERDcyIgPSAicm95YWxibHVlMyIsIAogICAgICAgICAgICAgICJUIGNlbGxzIiA9ICJsaWdodHNreWJsdWUzIiwgIkxTRUMiID0gImFxdWFtYXJpbmUzIiwKICAgICAgICAgICAgICAib3RoZXIgRUNzIiA9ICJmb3Jlc3RncmVlbiIsICJCIGNlbGxzIiA9ICJkYXJrb3JjaGlkMSIsCiAgICAgICAgICAgICAgIkt1cGZmZXIgY2VsbHMiID0gInNreWJsdWUxIiwgIm90aGVyIE1vbm8tTWFjIiA9ICJzdGVlbGJsdWUzIiwgCiAgICAgICAgICAgICAgIklMQyIgPSAic2xhdGVibHVlMSIpCmBgYAoKCgojIEZpZ3VyZSAxCiMjIE1haW4gRmlndXJlClVNQVAgd2l0aCBhbGwgY2VsbCB0eXBlcwoKYGBge3J9CmhjZWxsc19jc3MgPSByZWFkUkRTKCJkYXRhL3Byb2Nlc3NlZC9oY2VsbHNfY3NzLlJEUyIpCmFsbGNlbGxzX2NzcyA9IHJlYWRSRFMoZmlsZSA9ICJkYXRhL3Byb2Nlc3NlZC9hbGxjZWxsc19jc3NfcmVhbm5vdC5SRFMiKQpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0PTIsIGZpZy53aWR0aD0zfQpwbG90X2RmID0gZGF0YS5mcmFtZShoY2VsbHNfY3NzQHJlZHVjdGlvbnMkdW1hcF9jc3NAY2VsbC5lbWJlZGRpbmdzKQpwbG90X2RmJG5hbWVzX21ham9yID0gYXMuY2hhcmFjdGVyKGhjZWxsc19jc3NAbWV0YS5kYXRhJG5hbWVzX21ham9yKQpwbG90X2RmJG5hbWVzX21ham9yW3Bsb3RfZGYkbmFtZXNfbWFqb3I9PSJUIGNlbGxzIiB8IAogICAgICAgICAgICAgICAgICAgICAgcGxvdF9kZiRuYW1lc19tYWpvcj09IkIgY2VsbHMiIHwgCiAgICAgICAgICAgICAgICAgICAgICBwbG90X2RmJG5hbWVzX21ham9yPT0iTWFjcm9waGFnZXMiIHwKICAgICAgICAgICAgICAgICAgICAgIHBsb3RfZGYkbmFtZXNfbWFqb3I9PSJEQ3MiXSA9ICJJbW11bmUiCnBsb3RfZGYkbmFtZXNfbWFqb3JbcGxvdF9kZiRuYW1lc19tYWpvcj09IlN0ZWxsYXRlIGNlbGxzIl0gPSAiTWVzZW5jaHltYWwiCnBsb3RfZGYkbmFtZXNfbWFqb3JbcGxvdF9kZiRuYW1lc19tYWpvcj09IkVuZG90aGVsaWFsIGNlbGxzIl0gPSAiRW5kb3RoZWxpYWwiCnBsdCA9IGdncGxvdChwbG90X2RmLCBhZXMoeCA9IFVNQUNTU18xLCB5ID0gVU1BQ1NTXzIsIGNvbG91ciA9IG5hbWVzX21ham9yKSkrCiAgZ2VvbV9wb2ludChzaXplID0gcG9pbnRzaXplKSsKICBndWlkZXMoY29sb3VyID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZSA9IDMpLCB0aXRsZSA9ICJDZWxsIFR5cGUiKSkrCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjb2xzbWFqb3IpKwogIHRoZW1lX2NsYXNzaWMoKSsKICB0aF9nZW4rCiAgdGhlbWUoYXhpcy5saW5lID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMCksCiAgICAgICAgYXNwZWN0LnJhdGlvID0gMSkKCnBkZigiZmlndXJlX3BhbmVscy9maWcxL3VtYXBfZnJlc2hfbWFqb3IucGRmIiwgCiAgICB1c2VEaW5nYmF0cyA9IEYsIGhlaWdodCA9IDQsIHdpZHRoID0gNSkKcHJpbnQocGx0KQpkZXYub2ZmKCkKcG5nKCJmaWd1cmVfcGFuZWxzL2ZpZzEvdW1hcF9mcmVzaF9tYWpvci5wbmciLCAKICAgIGhlaWdodD04LCB3aWR0aD04LCB1bml0PSJjbSIsIHJlcz02MDAsIGFudGlhbGlhcyA9ICJzdWJwaXhlbCIpCnByaW50KHBsdCkKZGV2Lm9mZigpCnBkZigiZmlndXJlX3BhbmVscy9maWcxL3VtYXBfZnJlc2hfbWFqb3Jfbm9MZWcucGRmIiwgCiAgICB1c2VEaW5nYmF0cyA9IEYsIGhlaWdodCA9IDQsIHdpZHRoID0gNSkKcHJpbnQocGx0K3RoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikpCmRldi5vZmYoKQpwbmcoImZpZ3VyZV9wYW5lbHMvZmlnMS91bWFwX2ZyZXNoX21ham9yX25vTGVnLnBuZyIsIAogICAgaGVpZ2h0PTgsIHdpZHRoPTgsIHVuaXQ9ImNtIiwgcmVzPTYwMCwgYW50aWFsaWFzID0gInN1YnBpeGVsIikKcHJpbnQocGx0K3RoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikpCmBgYAoKVU1BUCB3aXRoIGhlYWx0aHkgZG9ub3JzCgpgYGB7ciwgZmlnLmhlaWdodD0yLCBmaWcud2lkdGg9M30KcGxvdF9kZiA9IGRhdGEuZnJhbWUoaGNlbGxzX2Nzc0ByZWR1Y3Rpb25zJHVtYXBfY3NzQGNlbGwuZW1iZWRkaW5ncykKcGxvdF9kZiREb25vciA9IGZhY3RvcihoY2VsbHNfY3NzQG1ldGEuZGF0YSREb25vcikKcGxvdF9kZiREb25vciA9IHBseXI6OnJldmFsdWUocGxvdF9kZiREb25vciwgYygiSEQxIiA9ICJzY19IMSIsICJIRDIiID0gInNjX0gyIiwgIkhEMyIgPSAic2NfSDMiKSkKCnBsdCA9IGdncGxvdChwbG90X2RmW3NhbXBsZSgxOm5yb3cocGxvdF9kZiksIG5yb3cocGxvdF9kZiksIHJlcGxhY2UgPSBGKSxdLCAKICAgICAgICAgICAgIGFlcyh4ID0gVU1BQ1NTXzEsIHkgPSBVTUFDU1NfMiwgY29sb3VyID0gRG9ub3IpKSsKICBnZW9tX3BvaW50KHNpemUgPSBwb2ludHNpemUpKwogIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gMyksIHRpdGxlID0gIkRvbm9ycyIpKSsKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGNvbGRvbikrCiAgdGhlbWVfY2xhc3NpYygpKwogIHRoX2dlbisKICB0aGVtZShheGlzLmxpbmUgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwKSwKICAgICAgICBhc3BlY3QucmF0aW8gPSAxKQoKcGRmKCJmaWd1cmVfcGFuZWxzL2ZpZzEvdW1hcF9mcmVzaF9kb25vcnMucGRmIiwgCiAgICB1c2VEaW5nYmF0cyA9IEYsIGhlaWdodCA9IDQsIHdpZHRoID0gNSkKcHJpbnQocGx0KQpkZXYub2ZmKCkKcG5nKCJmaWd1cmVfcGFuZWxzL2ZpZzEvdW1hcF9mcmVzaF9kb25vcnMucG5nIiwgCiAgICBoZWlnaHQ9OCwgd2lkdGg9OCwgdW5pdD0iY20iLCByZXM9NjAwLCBhbnRpYWxpYXMgPSAic3VicGl4ZWwiKQpwcmludChwbHQpCmRldi5vZmYoKQpwZGYoImZpZ3VyZV9wYW5lbHMvZmlnMS91bWFwX2ZyZXNoX2Rvbm9yc19ub0xlZy5wZGYiLCAKICAgIHVzZURpbmdiYXRzID0gRiwgaGVpZ2h0ID0gNCwgd2lkdGggPSA1KQpwcmludChwbHQrdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSkKZGV2Lm9mZigpCnBuZygiZmlndXJlX3BhbmVscy9maWcxL3VtYXBfZnJlc2hfZG9ub3JzX25vTGVnLnBuZyIsIAogICAgaGVpZ2h0PTgsIHdpZHRoPTgsIHVuaXQ9ImNtIiwgcmVzPTYwMCwgYW50aWFsaWFzID0gInN1YnBpeGVsIikKcHJpbnQocGx0K3RoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikpCmRldi5vZmYoKQpgYGAKClZpb2xpbnMgZm9yIGNlbGwgdHlwZSBtYXJrZXJzCgpgYGB7cn0KbWFya2VycyA9IGMoIkFTR1IxIiwgIkFQT0IiLCAiQVBPQzMiLAogICAgICAgICAgICAiS1JUNyIsIkNMRE40IiwiRVBDQU0iLAogICAgICAgICAgICAiQ0xFQzRHIiwiUEVDQU0xIiwiQ0QzNiIsCiAgICAgICAgICAgICJEQ04iLCJDT0xFQzExIiwiQUNUQTIiLAogICAgICAgICAgICAiUFRQUkMiLCJITEEtRFFBMSIsIkxZWiIpCmBgYAoKYGBge3IsIGZpZy53aWR0aD0zLjQsIGZpZy5oZWlnaHQ9NC42fQpleHBfbWsgPSBkYXRhLmZyYW1lKE1hdHJpeDo6dChoY2VsbHNfY3NzQGFzc2F5cyRTQ1RAZGF0YVttYXJrZXJzLF0pKQpwbG90X2RmID0gY2JpbmQoZXhwX21rLCAKICAgICAgICAgICAgICAgIGRhdGEuZnJhbWUobmFtZXNfbWFqb3IgPSBhcy5jaGFyYWN0ZXIoaGNlbGxzX2Nzc0BtZXRhLmRhdGFbLGMoIm5hbWVzX21ham9yIildKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0cmluZ3NBc0ZhY3RvcnMgPSBGKSkKcGxvdF9kZiRuYW1lc19tYWpvcltwbG90X2RmJG5hbWVzX21ham9yPT0iVCBjZWxscyIgfCAKICAgICAgICAgICAgICAgICAgICAgIHBsb3RfZGYkbmFtZXNfbWFqb3I9PSJCIGNlbGxzIiB8IAogICAgICAgICAgICAgICAgICAgICAgcGxvdF9kZiRuYW1lc19tYWpvcj09Ik1hY3JvcGhhZ2VzIiB8IAogICAgICAgICAgICAgICAgICAgICAgcGxvdF9kZiRuYW1lc19tYWpvcj09IkRDcyJdID0gIkltbXVuZSIKcGxvdF9kZiRuYW1lc19tYWpvcltwbG90X2RmJG5hbWVzX21ham9yPT0iRW5kb3RoZWxpYWwgY2VsbHMiXSA9ICJFbmRvdGhlbGlhbCIKcGxvdF9kZiRuYW1lc19tYWpvcltwbG90X2RmJG5hbWVzX21ham9yPT0iU3RlbGxhdGUgY2VsbHMiXSA9ICJNZXNlbmNoeW1hbCIKcGxvdF9kZiA9IHBsb3RfZGZbcGxvdF9kZiRuYW1lc19tYWpvciE9IkRvdWJsZXRzIixdCnBsb3RfZGYkbmFtZXNfbWFqb3IgPSBmYWN0b3IocGxvdF9kZiRuYW1lc19tYWpvciwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygiSGVwYXRvY3l0ZXMiLCAiQ2hvbGFuZ2lvY3l0ZXMiLCAiRW5kb3RoZWxpYWwiLCAiTWVzZW5jaHltYWwiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkltbXVuZSIpKQpwbG90X2RmID0gcmVzaGFwZTI6Om1lbHQocGxvdF9kZikKcGxvdF9kZiR2YXJpYWJsZSA9IGZhY3Rvcihnc3ViKCIuIiwgIi0iLCBwbG90X2RmJHZhcmlhYmxlLCBmaXhlZCA9IFQpLCBsZXZlbHMgPSBtYXJrZXJzKQoKdmlvX21rID0gZ2dwbG90KHBsb3RfZGYsIGFlcyh4ID0gbmFtZXNfbWFqb3IsIHkgPSB2YWx1ZSwgZmlsbCA9IG5hbWVzX21ham9yKSkrCiAgZmFjZXRfZ3JpZCh2YXJpYWJsZX5uYW1lc19tYWpvciwgc2NhbGVzID0gImZyZWUiKSsKICBnZW9tX3Zpb2xpbihzY2FsZSA9ICJ3aWR0aCIsIHNpemUgPSAwLjMpKwogIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMCwxMCwyKSwgbGFiZWxzID0gc2VxKDAsMTAsMiksIG5hbWUgPSAibG9nKGV4cCsxKSIpKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNvbHNtYWpvcikrCiAgdGhlbWUoc3RyaXAuYmFja2dyb3VuZC55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHN0cmlwLmJhY2tncm91bmQueCA9IGVsZW1lbnRfcmVjdChmaWxsID0gInRyYW5zcGFyZW50IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9ICJibGFjayIsIHNpemUgPSAwLjgpLAogICAgICAgIHN0cmlwLnRleHQueSA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDAsIHNpemUgPSA2LjUsIGNvbG91ciA9ICJibGFjayIsIGZhY2UgPSAiYm9sZCIpLAogICAgICAgIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiLCBzaXplID0gNi41LCBjb2xvdXIgPSAiYmxhY2siKSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICBheGlzLmxpbmUueC5ib3R0b20gPSBlbGVtZW50X2JsYW5rKCkpCgpwZGYoImZpZ3VyZV9wYW5lbHMvZmlnMS92aW9saW5fbWFya2Vyc19tYWpvci5wZGYiLCAKICAgIHVzZURpbmdiYXRzID0gRiwgaGVpZ2h0ID0gNSwgd2lkdGggPSA1LjUpCnByaW50KHZpb19taykKZGV2Lm9mZigpCnBuZygiZmlndXJlX3BhbmVscy9maWcxL3Zpb2xpbl9tYXJrZXJzX21ham9yLnBuZyIsIGhlaWdodCA9IDQyNSwgd2lkdGggPSA0NTAsIGFudGlhbGlhcyA9ICJzdWJwaXhlbCIpCnByaW50KHZpb19taykKZGV2Lm9mZigpCmBgYAoKSGVhdG1hcCBmb3IgbWFqb3IgY2VsbCB0eXBlcwoKYGBge3J9CiMgcmVtb3ZlZCBISElQCm5tZz1jKCJQREdGUkEiLCJDQUxEMSIsIkNPTDZBMSIsIlBER0ZSQiIsCiAgICAgICJDU0YxUiIsIkNEMTYzIiwiTUFSQ08iLCJDRDY5IiwiSUw3UiIsIlBDSzEiLCJDWVAyQTciLCJDWVAzQTQiLCJDUlAiLAogICAgICAiUk9CTzQiLCJFR0ZMNyIsIkNMRUM0TSIsIkZDTjIiLCJLUlQ3IiwiQ0ZUUiIsIk9ORUNVVDEiKQpwbG90X2RmID0gZGF0YS5mcmFtZShyb3cubmFtZXMgPSByb3duYW1lcyhoY2VsbHNfY3NzQG1ldGEuZGF0YSksCiAgICAgICAgICAgICAgICAgICAgIG5hbWVzX21ham9yID0gYXMuY2hhcmFjdGVyKGhjZWxsc19jc3NAbWV0YS5kYXRhWyxjKCJuYW1lc19tYWpvciIpXSksCiAgICAgICAgICAgICAgICAgICAgIGRvbm9yID0gYXMuY2hhcmFjdGVyKGhjZWxsc19jc3NAbWV0YS5kYXRhWyxjKCJEb25vciIpXSksCiAgICAgICAgICAgICAgICAgICAgIHN0cmluZ3NBc0ZhY3RvcnMgPSBGKSAKcGxvdF9kZiRuYW1lc19tYWpvcltwbG90X2RmJG5hbWVzX21ham9yPT0iVCBjZWxscyIgfCAKICAgICAgICAgICAgICAgICAgICAgIHBsb3RfZGYkbmFtZXNfbWFqb3I9PSJCIGNlbGxzIiB8IAogICAgICAgICAgICAgICAgICAgICAgcGxvdF9kZiRuYW1lc19tYWpvcj09Ik1hY3JvcGhhZ2VzIiB8IAogICAgICAgICAgICAgICAgICAgICAgcGxvdF9kZiRuYW1lc19tYWpvcj09IkRDcyJdID0gIkltbXVuZSIKcGxvdF9kZiRuYW1lc19tYWpvcltwbG90X2RmJG5hbWVzX21ham9yPT0iRW5kb3RoZWxpYWwgY2VsbHMiXSA9ICJFbmRvdGhlbGlhbCIKcGxvdF9kZiRuYW1lc19tYWpvcltwbG90X2RmJG5hbWVzX21ham9yPT0iU3RlbGxhdGUgY2VsbHMiXSA9ICJNZXNlbmNoeW1hbCIKcGxvdF9kZiA9IHBsb3RfZGZbcGxvdF9kZiRuYW1lc19tYWpvciE9IkRvdWJsZXRzIixdCnBsb3RfZGYgPSBwbG90X2RmW29yZGVyKHBsb3RfZGYkbmFtZXNfbWFqb3IpLF0KbTE9R2V0QXNzYXlEYXRhKGhjZWxsc19jc3MsIHNsb3Q9ImRhdGEiKVtubWcscm93bmFtZXMocGxvdF9kZildCm0xID0gdChhcHBseShtMSwgMSwgc2NhbGUsIHNjYWxlID0gRikpCmNvbG5hbWVzKG0xKT1yZXAoIiIsbmNvbChtMSkpCmNvdWwgPC0gY29sb3JSYW1wUGFsZXR0ZShicmV3ZXIucGFsKDksICJHcmV5cyIpKSgxMDApWy1jKDE6NSldCm0xW20xPjFdID0gMQojbTFbbTE8PSgtMildID0gLTIKaGVhdG1hcChtMSxSb3d2ID0gTkEsQ29sdiA9IE5BLCBjb2w9Y291bCkKYGBgCgpWaW9saW5zIGZvciBhbGwgY2VsbCB0eXBlcwoKYGBge3IsIGZpZy53aWR0aD0zLjQsIGZpZy5oZWlnaHQ9NC42fQpleHBfbWsgPSBkYXRhLmZyYW1lKE1hdHJpeDo6dChoY2VsbHNfY3NzQGFzc2F5cyRTQ1RAZGF0YVttYXJrZXJzLF0pKQpwbG90X2RmID0gY2JpbmQoZXhwX21rLCAKICAgICAgICAgICAgICAgIGhjZWxsc19jc3NAbWV0YS5kYXRhWyxjKCJuYW1lc19tYWpvciIsIm5hbWVzX2NsdXN0ZXJzIildKQpwbG90X2RmJG5hbWVzX21ham9yID0gYXMuY2hhcmFjdGVyKHBsb3RfZGYkbmFtZXNfbWFqb3IpCnBsb3RfZGYkbmFtZXNfbWFqb3JbcGxvdF9kZiRuYW1lc19tYWpvcj09IlQgY2VsbHMiIHwgCiAgICAgICAgICAgICAgICAgICAgICBwbG90X2RmJG5hbWVzX21ham9yPT0iQiBjZWxscyIgfCAKICAgICAgICAgICAgICAgICAgICAgIHBsb3RfZGYkbmFtZXNfbWFqb3I9PSJNYWNyb3BoYWdlcyIgfCAKICAgICAgICAgICAgICAgICAgICAgIHBsb3RfZGYkbmFtZXNfbWFqb3I9PSJEQ3MiXSA9ICJJbW11bmUiCnBsb3RfZGYkbmFtZXNfbWFqb3JbcGxvdF9kZiRuYW1lc19tYWpvcj09IkVuZG90aGVsaWFsIGNlbGxzIl0gPSAiRW5kb3RoZWxpYWwiCnBsb3RfZGYkbmFtZXNfbWFqb3JbcGxvdF9kZiRuYW1lc19tYWpvcj09IlN0ZWxsYXRlIGNlbGxzIl0gPSAiTWVzZW5jaHltYWwiCnBsb3RfZGYgPSBwbG90X2RmW3Bsb3RfZGYkbmFtZXNfbWFqb3IhPSJEb3VibGV0cyIsXQpwbG90X2RmJG5hbWVzX21ham9yID0gZmFjdG9yKHBsb3RfZGYkbmFtZXNfbWFqb3IsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIkhlcGF0b2N5dGVzIiwgIkNob2xhbmdpb2N5dGVzIiwgIkVuZG90aGVsaWFsIiwgIk1lc2VuY2h5bWFsIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJJbW11bmUiKSkKcGxvdF9kZiA9IHJlc2hhcGUyOjptZWx0KHBsb3RfZGYpCnBsb3RfZGYkdmFyaWFibGUgPSBmYWN0b3IoZ3N1YigiLiIsICItIiwgcGxvdF9kZiR2YXJpYWJsZSwgZml4ZWQgPSBUKSwgbGV2ZWxzID0gbWFya2VycykKCmdncGxvdChwbG90X2RmLCBhZXMoeCA9IG5hbWVzX2NsdXN0ZXJzLCB5ID0gdmFsdWUsIGZpbGwgPSBuYW1lc19jbHVzdGVycykpKwogIGZhY2V0X2dyaWQodmFyaWFibGV+bmFtZXNfbWFqb3IsIHNjYWxlcyA9ICJmcmVlIikrCiAgZ2VvbV92aW9saW4oc2NhbGUgPSAid2lkdGgiKSsKICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsMTAsMiksIGxhYmVscyA9IHNlcSgwLDEwLDIpLCBuYW1lID0gImxvZyhleHArMSkiKSsKICAjc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY29sc21ham9yKSsKICB0aGVtZShzdHJpcC5iYWNrZ3JvdW5kLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgc3RyaXAuYmFja2dyb3VuZC54ID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gImJsYWNrIiwgc2l6ZSA9IDAuOCksCiAgICAgICAgc3RyaXAudGV4dC55ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMCwgc2l6ZSA9IDYuNSwgY29sb3VyID0gImJsYWNrIiwgZmFjZSA9ICJib2xkIiksCiAgICAgICAgc3RyaXAudGV4dC54ID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIsIHNpemUgPSA2LjUsIGNvbG91ciA9ICJibGFjayIpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IC0zNSwgaGp1c3QgPSAwLCB2anVzdCA9IDAuMSksCiAgICAgICAgYXhpcy5saW5lLnguYm90dG9tID0gZWxlbWVudF9ibGFuaygpKQpgYGAKCkNlbGwgdHlwZSBwcm9wb3J0aW9ucwoKYGBge3J9CnBsb3RfZGYgPSBkYXRhLmZyYW1lKCJuYW1lc19tYWpvciIgPSBhcy5jaGFyYWN0ZXIoaGNlbGxzX2Nzc0BtZXRhLmRhdGEkbmFtZXNfbWFqb3IpLAogICAgICAgICAgICAgICAgICAgICAiRG9ub3IiID0gYXMuY2hhcmFjdGVyKGhjZWxsc19jc3NAbWV0YS5kYXRhJERvbm9yKSwKICAgICAgICAgICAgICAgICAgICAgc3RyaW5nc0FzRmFjdG9ycyA9IEYpCnBsb3RfZGYkbmFtZXNfbWFqb3JbcGxvdF9kZiRuYW1lc19tYWpvcj09IlQgY2VsbHMiIHwgCiAgICAgICAgICAgICAgICAgICAgICBwbG90X2RmJG5hbWVzX21ham9yPT0iQiBjZWxscyIgfCAKICAgICAgICAgICAgICAgICAgICAgIHBsb3RfZGYkbmFtZXNfbWFqb3I9PSJNYWNyb3BoYWdlcyIgfCAKICAgICAgICAgICAgICAgICAgICAgIHBsb3RfZGYkbmFtZXNfbWFqb3I9PSJEQ3MiXSA9ICJJbW11bmUiCnBsb3RfZGYkbmFtZXNfbWFqb3JbcGxvdF9kZiRuYW1lc19tYWpvcj09IkVuZG90aGVsaWFsIGNlbGxzIl0gPSAiRW5kb3RoZWxpYWwiCnBsb3RfZGYkbmFtZXNfbWFqb3JbcGxvdF9kZiRuYW1lc19tYWpvcj09IlN0ZWxsYXRlIGNlbGxzIl0gPSAiTWVzZW5jaHltYWwiCnBsb3RfZGYgPSBwbG90X2RmW3Bsb3RfZGYkbmFtZXNfbWFqb3IhPSJEb3VibGV0cyIsXQpjbnRzX2N0ID0gdGFibGUocGxvdF9kZiRuYW1lc19tYWpvciwgcGxvdF9kZiREb25vcikKcGxvdF9kZiA9IHJlc2hhcGUyOjptZWx0KGFwcGx5KGNudHNfY3QsIDEsIGZ1bmN0aW9uKHgpIHgvc3VtKHgpKSkKI3Bsb3RfZGYkVmFyMiA9IGZhY3RvcihwbG90X2RmJFZhcjIsIAojICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIkhlcGF0b2N5dGVzIiwgIkNob2xhbmdpb2N5dGVzIiwgIkVuZG90aGVsaWFsIiwiTWVzZW5jaHltYWwiLCAiSW1tdW5lIikpCnBsb3RfZGYkVmFyMSA9IHBseXI6OnJldmFsdWUocGxvdF9kZiRWYXIxLCBjKCJIRDEiID0gInNjX0gxIiwgIkhEMiIgPSAic2NfSDIiLCAiSEQzIiA9ICJzY19IMyIpKQpwbG90X2RmJFZhcjEgPSBmYWN0b3IocGxvdF9kZiRWYXIxLCBsZXZlbHMgPSByZXYobGV2ZWxzKHBsb3RfZGYkVmFyMSkpKQoKcGx0ID0gZ2dwbG90KHBsb3RfZGYsIGFlcyh4ID0gVmFyMiwgeSA9IHZhbHVlKjEwMCwgZmlsbCA9IFZhcjEpKSsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikrCiAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwwKSkrCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY29sZG9uKSsKICBsYWJzKHkgPSAiQ2VsbCB0eXBlIHByb3BvcnRpb24gWyVdIiwgeCA9IE5VTEwpKwogIHRoZW1lX2NsYXNzaWMoKSsKICB0aF9nZW4rCiAgdGhlbWUoYXhpcy5saW5lLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aWNrcy55ID0gZWxlbWVudF9saW5lKCksCiAgICAgICAgYXhpcy50aWNrcy54ID0gZWxlbWVudF9ibGFuaygpKQoKcGRmKCJmaWd1cmVfcGFuZWxzL2ZpZzEvcHJvcG9ydGlvbnNfZnJlc2hfbWFqb3JfZG9ub3IucGRmIiwgCiAgICB1c2VEaW5nYmF0cyA9IEYsIGhlaWdodCA9IDQsIHdpZHRoID0gNSkKcHJpbnQocGx0KQpkZXYub2ZmKCkKcG5nKCJmaWd1cmVfcGFuZWxzL2ZpZzEvcHJvcG9ydGlvbnNfZnJlc2hfbWFqb3JfZG9ub3IucG5nIiwgCiAgICBoZWlnaHQgPSAzMjUsIHdpZHRoID0gNDAwLCBhbnRpYWxpYXMgPSAic3VicGl4ZWwiKQpwcmludChwbHQpCmRldi5vZmYoKQpwZGYoImZpZ3VyZV9wYW5lbHMvZmlnMS9wcm9wb3J0aW9uc19mcmVzaF9tYWpvcl9kb25vcl9ub0xlZy5wZGYiLCAKICAgIHVzZURpbmdiYXRzID0gRiwgaGVpZ2h0ID0gNCwgd2lkdGggPSA1KQpwcmludChwbHQrdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSkKZGV2Lm9mZigpCnBuZygiZmlndXJlX3BhbmVscy9maWcxL3Byb3BvcnRpb25zX2ZyZXNoX21ham9yX2Rvbm9yX25vTGVnLnBuZyIsIAogICAgaGVpZ2h0ID0gMzI1LCB3aWR0aCA9IDQwMCwgYW50aWFsaWFzID0gInN1YnBpeGVsIikKcHJpbnQocGx0K3RoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikpCmRldi5vZmYoKQpgYGAKCkltcG9ydCBtYXJrZXJzCgpgYGB7cn0KbWFya2VycyA9IGMoIkFTR1IxIiwgIkFQT0IiLCAiQVBPQzMiLCAiQ1lQMkUxIiwgIkhBTVAiLCAiT1JNMSIsICJTQUExIiwgIk5OTVQiLCAiRkFCUDEiLCAiTVQxRyIsICJPUk0yIiwgIlRUUiIsICJIUCIsICJBUE9DMSIsICJBUE9BMiIsIkZHQiIsIkNZUDNBNCIsIkNQUzEiLCJBUkcxIiwiU0FBMiIsIyBIZXAKICAgICAgICAgICAgIktSVDciLCJDTERONCIsIkVQQ0FNIiwgIlRBQ1NURDIiLCAiQ0QyNCIsICJLUlQxOSIsICJBTlhBNCIsICJDWENMNiIsICJGWFlEMiIsICJTT1g0IiwgICJDUllBQiIsIkRFRkIxIiwiU0xDMTJBMiIsIk1NUDciLCJUTkZSU0YxMkEiLCJDWENMMSIsIkJJQ0MxIiwiUzEwMEExNCIsIkRDREMyIiwiUExQUDIiLCMgQ2hvCiAgICAgICAgICAgICJDTEVDNEciLCJQRUNBTTEiLCJDRDM2IiwgIkZDTjMiLCAiRE5BU0UxTDMiLCAiQ0xFQzFCIiwgIkNSSEJQIiwgIkFLQVAxMiIsICJJRkkyNyIsICJHTkcxMSIsICJJTDMzIiwiRkxUMSIsIlBSU1MyMyIsIkVORyIsIlJBTVAzIiwiRjgiLCJWV0YiLCJDTERONSIsIkNDTDE0IiwiTFlWRTEiLCMgRW5kCiAgICAgICAgICAgICJEQ04iLCJDT0xFQzExIiwiQUNUQTIiLCAiQ0NMMiIsICJUQUdMTiIsICJJR0ZCUDMiLCAiQkdOIiwgIkxVTSIsICJDT0wzQTEiLCAiTVlMOSIsICJUUE0yIiwiQUVCUDEiLCJHR1Q1IiwiQVNQTiIsIkNPTDE0QTEiLCJQVEdEUyIsIkNPTDZBMSIsIkNZUjYxIiwiQ09MRUMxMCIsIkNYQ0wxMiIsIyBNZXMKICAgICAgICAgICAgIlBUUFJDIiwiSExBLURRQTEiLCJMWVoiLCAiTElMUkIyIiwgIk1BUkNPIiwgIkMxUUIiLCAiRkNHUjNBIiwgICJOS0c3IiwgIk1TNEExIiwgIk1aQjEiLCAiQ0NMNSIsIktMUkQxIiwiQVJFRyIsIk1TNEE3IiwiQVhMIiwiQ0Q2OSIsIkdQUjE4MyIsIlRMUjIiLCJDRDQ0IiwiSUw3UiIpICMgSW1tCm1rX2xpc3QgPSBsaXN0KCJIZXBhdG9jeXRlcyIgPSBtYXJrZXJzWzE6MTBdLCAiQ2hvbGFuZ2lvY3l0ZXMiID0gbWFya2Vyc1syMTozMF0sIAogICAgICAgICAgICAgICAiRW5kb3RoZWxpYWwiID0gbWFya2Vyc1s0MTo1MF0sICJNZXNlbmNoeW1hbCIgPSBtYXJrZXJzWzYxOjcwXSwgIkltbXVuZSIgPSBtYXJrZXJzWzgxOjkwXSkKCmNlbGxfdHlwZV9tayA9IHJlYWRSRFMoZmlsZSA9ICJyZXN1bHRzL2ludGVncl9hbGxjZWxscy9jZWxsX3R5cGVfbWtfbWFqb3IuUkRTIikKZnJlc2hfZGUgPSBsaXN0KCkKZm9yKG4gaW4gdW5pcXVlKGNlbGxfdHlwZV9tayRtYWpvcl9hbGwkY2x1c3RlcikpewogIGZyZXNoX2RlW1tuXV0gPSBjZWxsX3R5cGVfbWskbWFqb3JfYWxsW2NlbGxfdHlwZV9tayRtYWpvcl9hbGwkY2x1c3Rlcj09bixdCn0KCmxvYWQoImRhdGEvcHJvY2Vzc2VkL3JlY2VpdmVkX0FnYS9ERV90YWJsZXNfY2VsbHR5cGVfZnJvemVuU0NULnJkYXRhIikKZnJvemVuX2RlID0gbGlzdCgiQ2hvbGFuZ2lvY3l0ZXMiID0gY2VsbF90eXBlX21rX2NobywgIkhlcGF0b2N5dGVzIiA9IGNlbGxfdHlwZV9ta19oZXAsIAogICAgICAgICAgICAgICAgICJFbmRvdGhlbGlhbCIgPSBjZWxsX3R5cGVfbWtfZWMsICJJbW11bmUiID0gY2VsbF90eXBlX21rX2ltbSwgCiAgICAgICAgICAgICAgICAgIk1lc2VuY2h5bWFsIiA9IGNlbGxfdHlwZV9ta19tZXMpCmZvcihuIGluIG5hbWVzKGZyb3plbl9kZSkpewogIGZyb3plbl9kZVtbbl1dJGNsdXN0ZXIgPSBuCiAgZnJvemVuX2RlW1tuXV0kZ2VuZSA9IHJvd25hbWVzKGZyb3plbl9kZVtbbl1dKQp9Cgpib3RoX2xpc3QgPSBsaXN0KCkKdG9wX21rID0gbGlzdCgpCmZvcihuIGluIG5hbWVzKGZyZXNoX2RlKSl7CiAgYm90aF9ERSA9IG1lcmdlKGZyZXNoX2RlW1tuXV0sIGZyb3plbl9kZVtbbl1dLCBieSA9ICJnZW5lIiwgYWxsID0gVClbLGMoMSwzLDYsOSwxMildCiAgY29sbmFtZXMoYm90aF9ERSkgPSBjKCJnZW5lIiwgIkZDX2ZyZXNoIiwgInB2YWxfZnJlc2giLCAiRkNfZnJvemVuIiwgInB2YWxfZnJvemVuIikKICBib3RoX0RFJEZDX2ZyZXNoW2lzLm5hKGJvdGhfREUkRkNfZnJlc2gpXSA9IDAKICBib3RoX0RFJHB2YWxfZnJlc2hbaXMubmEoYm90aF9ERSRwdmFsX2ZyZXNoKV0gPSAxCiAgYm90aF9ERSRGQ19mcm96ZW5baXMubmEoYm90aF9ERSRGQ19mcm96ZW4pXSA9IDAKICBib3RoX0RFJHB2YWxfZnJvemVuW2lzLm5hKGJvdGhfREUkcHZhbF9mcm96ZW4pXSA9IDEKICBib3RoX0RFJGNlbGx0eXBlID0gbgogIGJvdGhfREUkcyA9IGJvdGhfREUkRkNfZnJlc2grYm90aF9ERSRGQ19mcm96ZW4KICBib3RoX0RFID0gYm90aF9ERVtvcmRlcihib3RoX0RFJHMsIGRlY3JlYXNpbmcgPSBUKSxdCiAgY29uZF9mYyA9IGJvdGhfREUkRkNfZnJlc2g+PTAuMSAmIGJvdGhfREUkRkNfZnJvemVuPj0wLjEKICBjb25kX3B2ID0gYm90aF9ERSRwdmFsX2ZyZXNoPD0wLjA1IHwgYm90aF9ERSRwdmFsX2Zyb3plbjw9MC4wNQogIGJvdGhfREUkaXNjb2wgPSBpZmVsc2UoY29uZF9mYyAmIGNvbmRfcHYsIAogICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGJvdGhfREUkZ2VuZSAlaW4lIG1rX2xpc3RbW25dXSwgImlzdG9wIiwgImlzREUiKSwgIm5vdERFIikKICBib3RoX0RFJGlzY29sID0gZmFjdG9yKGJvdGhfREUkaXNjb2wsIGxldmVscyA9IHJldihjKCJpc3RvcCIsICJpc0RFIiwgIm5vdERFIikpKQogIGJvdGhfREUkaXN0b3AgPSBib3RoX0RFJGdlbmUgJWluJSBta19saXN0W1tuXV0jWzE6M10KICBib3RoX2xpc3RbW25dXSA9IGJvdGhfREUKICB0b3BfbWtbW25dXSA9IGJvdGhfREUkZ2VuZVtjb25kX2ZjICYgY29uZF9wdl1bMToyMF0KfQp0b3BfbWsgPSB0b3BfbWtbYyg0LDEsMyw1LDIpXQpgYGAKCkhlYXRtYXAgcGVyIGNsdXN0ZXIKCmBgYHtyfQpjZWxsX3R5cGVfbWsgPSByZWFkUkRTKGZpbGUgPSAicmVzdWx0cy9jb25kX2VmZmVjdC9jZWxsX3R5cGVfbWsuUkRTIikKIyBjdXQgbWFya2VycyBoZXJlIGRlcGVuZGluZyBvbiB0aGUgc2l6ZSB5b3Ugd2FudCBmb3IgaGVhdG1hcCwgdGhlbiBhZGp1c3QgZmlndXJlCm1hcmtlcnMgPSBjKCJBU0dSMSIsICJBUE9CIiwgIkFQT0MzIiwgIkNZUDJFMSIsICJIQU1QIiwgIk9STTEiLCAiU0FBMSIsICJOTk1UIiwgIkZBQlAxIiwgIk1UMUciLCAiT1JNMiIsICJUVFIiLCAiSFAiLCAiQVBPQzEiLCAiQVBPQTIiLCJGR0IiLCJDWVAzQTQiLCJDUFMxIiwiQVJHMSIsIlNBQTIiLCMgSGVwCiAgICAgICAgICAgICJLUlQ3IiwiQ0xETjQiLCJFUENBTSIsICJUQUNTVEQyIiwgIkNEMjQiLCAiS1JUMTkiLCAiQU5YQTQiLCAiQ1hDTDYiLCAiRlhZRDIiLCAiU09YNCIsICAiQ1JZQUIiLCJERUZCMSIsIlNMQzEyQTIiLCJNTVA3IiwiVE5GUlNGMTJBIiwiQ1hDTDEiLCJCSUNDMSIsIlMxMDBBMTQiLCJEQ0RDMiIsIlBMUFAyIiwjIENobwogICAgICAgICAgICAiQ0xFQzRHIiwiUEVDQU0xIiwiQ0QzNiIsICJGQ04zIiwgIkROQVNFMUwzIiwgIkNMRUMxQiIsICJDUkhCUCIsICJBS0FQMTIiLCAiSUZJMjciLCAiR05HMTEiLCAiSUwzMyIsIkZMVDEiLCJQUlNTMjMiLCJFTkciLCJSQU1QMyIsIkY4IiwiVldGIiwiQ0xETjUiLCJDQ0wxNCIsIkxZVkUxIiwjIEVuZAogICAgICAgICAgICAiRENOIiwiQ09MRUMxMSIsIkFDVEEyIiwgIkNDTDIiLCAiVEFHTE4iLCAiSUdGQlAzIiwgIkJHTiIsICJMVU0iLCAiQ09MM0ExIiwgIk1ZTDkiLCAiVFBNMiIsIkFFQlAxIiwiR0dUNSIsIkFTUE4iLCJDT0wxNEExIiwiUFRHRFMiLCJDT0w2QTEiLCJDWVI2MSIsIkNPTEVDMTAiLCJDWENMMTIiLCMgTWVzCiAgICAgICAgICAgICJQVFBSQyIsIkhMQS1EUUExIiwiTFlaIiwgIkxJTFJCMiIsICJNQVJDTyIsICJDMVFCIiwgIkZDR1IzQSIsICAiTktHNyIsICJNUzRBMSIsICJNWkIxIiwgIkNDTDUiLCJLTFJEMSIsIkFSRUciLCJNUzRBNyIsIkFYTCIsIkNENjkiLCJHUFIxODMiLCJUTFIyIiwiQ0Q0NCIsIklMN1IiKSAjIEltbQptYXJrZXJzX3RvcGJvdGggPSB1bmxpc3QodG9wX21rKQptYXJrZXJzID0gbWFya2Vyc190b3Bib3RoCgpsb2FkKCJkYXRhL3Byb2Nlc3NlZC9yZWNlaXZlZF9BZ2EvbWVhbl9leHBfY2VsbHR5cGVfZnJvemVuLnJkYXRhIikKaGNlbGxzX2Nzc0BtZXRhLmRhdGEkbWFqb3JfY3QgPSBhcy5jaGFyYWN0ZXIoaGNlbGxzX2Nzc0BtZXRhLmRhdGEkbmFtZXNfbWFqb3IpCmhjZWxsc19jc3NAbWV0YS5kYXRhJG1ham9yX2N0W2hjZWxsc19jc3NAbWV0YS5kYXRhJG1ham9yX2N0PT0iVCBjZWxscyIgfCAKICAgICAgICAgICAgICAgICAgICAgIGhjZWxsc19jc3NAbWV0YS5kYXRhJG1ham9yX2N0PT0iQiBjZWxscyIgfCAKICAgICAgICAgICAgICAgICAgICAgIGhjZWxsc19jc3NAbWV0YS5kYXRhJG1ham9yX2N0PT0iTWFjcm9waGFnZXMiIHwKICAgICAgICAgICAgICAgICAgICAgIGhjZWxsc19jc3NAbWV0YS5kYXRhJG1ham9yX2N0PT0iRENzIl0gPSAiSW1tdW5lIgpoY2VsbHNfY3NzQG1ldGEuZGF0YSRtYWpvcl9jdFtoY2VsbHNfY3NzQG1ldGEuZGF0YSRtYWpvcl9jdD09IlN0ZWxsYXRlIGNlbGxzIl0gPSAiTWVzZW5jaHltYWwiCmhjZWxsc19jc3NAbWV0YS5kYXRhJG1ham9yX2N0W2hjZWxsc19jc3NAbWV0YS5kYXRhJG1ham9yX2N0PT0iRW5kb3RoZWxpYWwgY2VsbHMiXSA9ICJFbmRvdGhlbGlhbCIKbV9jdF9mcmVzaCA9IGFwcGx5KGFzLm1hdHJpeChoY2VsbHNfY3NzQGFzc2F5cyRTQ1RAZGF0YSksIDEsIAogICAgICAgICAgICAgICAgICAgZnVuY3Rpb24oeCkgdGFwcGx5KHgsIGhjZWxsc19jc3NAbWV0YS5kYXRhJG1ham9yX2N0LCBtZWFuKSkKCm1fY3RfZnJvemVuID0gdChtX2N0X2Zyb3plbikKbV9jdF9mcm96ZW4gPSB0KGFwcGx5KG1fY3RfZnJvemVuLCAxLCBzY2FsZSkpCmNvbG5hbWVzKG1fY3RfZnJvemVuKSA9IHJvd25hbWVzKG1fY3RfZnJlc2gpWy0yXQptX2N0X2ZyZXNoID0gdChtX2N0X2ZyZXNoKVssLTJdCm1fY3RfZnJlc2ggPSB0KGFwcGx5KG1fY3RfZnJlc2gsIDEsIHNjYWxlKSkKY29sbmFtZXMobV9jdF9mcmVzaCkgPSBjb2xuYW1lcyhtX2N0X2Zyb3plbikKCm1lYW5fY3QgPSBtZXJnZShtX2N0X2ZyZXNoLCBtX2N0X2Zyb3plbiwgYnkgPSAwKQpyb3duYW1lcyhtZWFuX2N0KSA9IG1lYW5fY3RbLDFdCm1lYW5fY3QgPSBtZWFuX2N0WywtMV0KY29sbmFtZXMobWVhbl9jdCkgPSBwYXN0ZTAocmVwKGNvbG5hbWVzKG1fY3RfZnJlc2gpLCAyKSwgcmVwKGMoIl9mcmVzaCIsICJfZnJvemVuIiksIGVhY2ggPSA1KSkKCmhjbCA9IGhjbHVzdChkaXN0KHQobWVhbl9jdCkpLCBtZXRob2QgPSAid2FyZC5EMiIpCnBsb3QoaGNsKQoKYW5ub3RfZGYgPSBkYXRhLmZyYW1lKHJvdy5uYW1lcyA9IGNvbG5hbWVzKG1lYW5fY3QpLAogICAgICAgICAgICAgICAgICAgICAgImNlbGwgdHlwZSIgPSB1bmxpc3QobGFwcGx5KHN0cnNwbGl0KGNvbG5hbWVzKG1lYW5fY3QpLCAiXyIpLCBmdW5jdGlvbih4KSB4WzFdKSksCiAgICAgICAgICAgICAgICAgICAgICAicHJvY2Vzc2luZyIgPSB1bmxpc3QobGFwcGx5KHN0cnNwbGl0KGNvbG5hbWVzKG1lYW5fY3QpLCAiXyIpLCBmdW5jdGlvbih4KSB4WzJdKSkpCgpjYWxsYmFjayA9IGZ1bmN0aW9uKGhjLCBtYXQpewogIHN2ID0gc3ZkKHQobWF0KSkkdlssMl0KICAgIGRlbmQgPSByZW9yZGVyKGFzLmRlbmRyb2dyYW0oaGMpLCBjKDE6NCwpKQogICAgYXMuaGNsdXN0KGRlbmQpCn0KCnBkZigiZmlndXJlX3BhbmVscy9maWcxL21ham9yX2NlbGx0eXBlc19oZWF0bWFwX2ZyZXNoZnJvemVuXzEwLnBkZiIsIAogICAgdXNlRGluZ2JhdHMgPSBGLCBoZWlnaHQgPSA3LjUsIHdpZHRoID0gNikKaGVhdCA9IHBoZWF0bWFwOjpwaGVhdG1hcChtZWFuX2N0W21hcmtlcnNbYyg0MTo1MCwgNjE6NzAsIDgxOjkwLCAgMToxMCwgMjE6MzApXSxdLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBjbHVzdGVyaW5nX21ldGhvZCA9ICJ3YXJkLkQyIiwgdHJlZWhlaWdodF9yb3cgPSAwLCBhbm5vdGF0aW9uX2NvbCA9IGFubm90X2RmLAogICAgICAgICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJfcm93cyA9IEYsIHRyZWVoZWlnaHRfY29sID0gMjAsIGZvbnRzaXplX3JvdyA9IDUuNSwKICAgICAgICAgICAgICAgICAgICAgICAgICBhbm5vdGF0aW9uX2NvbG9ycyA9IGxpc3QoInByb2Nlc3NpbmciID0gYygiZnJlc2giID0gIiNkNGQ0ZDQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiZnJvemVuIiA9ICIjNWQ1ZDVkIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjZWxsLnR5cGUiID0gY29sc21ham9yWy02XSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgc2hvd19jb2xuYW1lcyA9IEYsIAogICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gY29sb3JSYW1wUGFsZXR0ZShyZXYoYnJld2VyLnBhbChuID0gOSwgbmFtZSA9ICJSZEJ1IikpKSgxMDApKQpkZXYub2ZmKCkKYGBgCgpGQyBmcmVzaCB2cyBmcm96ZW4KCmBgYHtyfQpta19saXN0ID0gbGlzdCgiSGVwYXRvY3l0ZXMiID0gbWFya2Vyc1sxOjEwXSwgIkNob2xhbmdpb2N5dGVzIiA9IG1hcmtlcnNbMjE6MzBdLCAKICAgICAgICAgICAgICAgIkVuZG90aGVsaWFsIiA9IG1hcmtlcnNbNDE6NTBdLCAiTWVzZW5jaHltYWwiID0gbWFya2Vyc1s2MTo3MF0sICJJbW11bmUiID0gbWFya2Vyc1s4MTo5MF0pCgpwbHRfZmNfbGlzdCA9IGxpc3QoKQpwZGYoImZpZ3VyZV9wYW5lbHMvZmlnMS9tYWpvcl9jZWxsdHlwZXNfRkNzY2F0dGVyXzEwLnBkZiIsIAogICAgdXNlRGluZ2JhdHMgPSBGLCBoZWlnaHQgPSA1LCB3aWR0aCA9IDQuNSkKZm9yKG4gaW4gbmFtZXMoYm90aF9saXN0KSl7CiAgYm90aF9ERSA9IGJvdGhfbGlzdFtbbl1dCiAgY2MgPSBjb3IoYm90aF9ERSRGQ19mcmVzaCwgYm90aF9ERSRGQ19mcm96ZW4pCiAgYm90aF9ERSA9IGJvdGhfREVbb3JkZXIoYm90aF9ERSRpc2NvbCksXQogIAogIGNvbHNfdXNlID0gYygiaXN0b3AiID0gdW5uYW1lKGNvbHNtYWpvcltuXSksICJpc0RFIiA9ICJncmV5MzUiLCAibm90REUiID0gImdyZXk4NSIpCiAgcGx0ID0gZ2dwbG90KGJvdGhfREUsIGFlcyh4ID0gRkNfZnJlc2gsIHkgPSBGQ19mcm96ZW4sIGNvbG91ciA9IGlzY29sKSkrCiAgICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLCBjb2xvdXIgPSAiZ3JleTQwIikrCiAgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBjb2xvdXIgPSAiZ3JleTQwIikrCiAgICBnZW9tX3BvaW50KCkrCiAgICBnZW9tX3RleHRfcmVwZWwoZGF0YSA9IGJvdGhfREVbYm90aF9ERSRpc3RvcCAmIGJvdGhfREUkaXNjb2w9PSJpc3RvcCIsXSwgbWFwcGluZyA9IGFlcyhsYWJlbCA9IGdlbmUpLAogICAgICAgICAgICAgICAgICAgIGZvbnRmYWNlID0gImJvbGQiKSsKICAgIHRoZW1lX2J3KCkrCiAgICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGNvbHNfdXNlKSsKICAgIGxhYnModGl0bGUgPSBuLCBzdWJ0aXRsZSA9IHBhc3RlMCgiUENDID0gIiwgcm91bmQoY2MsIDIpKSkrCiAgICB0aGVtZShhc3BlY3QucmF0aW8gPSAxLAogICAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KGNvbG91ciA9ICJibGFjayIpLAogICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLCAKICAgICAgICAgIHBhbmVsLmdyaWQgPSBlbGVtZW50X2JsYW5rKCkpCiAgCiAgcGx0X2ZjX2xpc3RbW25dXSA9IHBsdAogIHByaW50KHBsdCkKfQpkZXYub2ZmKCkKYGBgCgpFeHByZXNzaW9uIGNvbXBhcmlzb24gZnJlc2ggdnMgZnJvemVuCgpgYGB7cn0KbG9hZCgiZGF0YS9wcm9jZXNzZWQvcmVjZWl2ZWRfQWdhL21lYW5fZXhwX2NlbGx0eXBlX2Zyb3plbkNPVU5UUy5yZGF0YSIpCmhjZWxsc19jc3NAbWV0YS5kYXRhJG1ham9yX2N0ID0gYXMuY2hhcmFjdGVyKGhjZWxsc19jc3NAbWV0YS5kYXRhJG5hbWVzX21ham9yKQpoY2VsbHNfY3NzQG1ldGEuZGF0YSRtYWpvcl9jdFtoY2VsbHNfY3NzQG1ldGEuZGF0YSRtYWpvcl9jdD09IlQgY2VsbHMiIHwgCiAgICAgICAgICAgICAgICAgICAgICBoY2VsbHNfY3NzQG1ldGEuZGF0YSRtYWpvcl9jdD09IkIgY2VsbHMiIHwgCiAgICAgICAgICAgICAgICAgICAgICBoY2VsbHNfY3NzQG1ldGEuZGF0YSRtYWpvcl9jdD09Ik1hY3JvcGhhZ2VzIiB8CiAgICAgICAgICAgICAgICAgICAgICBoY2VsbHNfY3NzQG1ldGEuZGF0YSRtYWpvcl9jdD09IkRDcyJdID0gIkltbXVuZSIKaGNlbGxzX2Nzc0BtZXRhLmRhdGEkbWFqb3JfY3RbaGNlbGxzX2Nzc0BtZXRhLmRhdGEkbWFqb3JfY3Q9PSJTdGVsbGF0ZSBjZWxscyJdID0gIk1lc2VuY2h5bWFsIgpoY2VsbHNfY3NzQG1ldGEuZGF0YSRtYWpvcl9jdFtoY2VsbHNfY3NzQG1ldGEuZGF0YSRtYWpvcl9jdD09IkVuZG90aGVsaWFsIGNlbGxzIl0gPSAiRW5kb3RoZWxpYWwiCm1fY3RfZnJlc2ggPSBhcHBseShhcy5tYXRyaXgoaGNlbGxzX2Nzc0Bhc3NheXMkU0NUQGNvdW50cyksIDEsIAogICAgICAgICAgICAgICAgICAgZnVuY3Rpb24oeCkgdGFwcGx5KHgsIGhjZWxsc19jc3NAbWV0YS5kYXRhJG1ham9yX2N0LCBtZWFuKSkKCm1fY3RfZnJvemVuID0gbG9nKHQobV9jdF9mcm96ZW4uY291bnRzKSkKI21fY3RfZnJvemVuID0gdChhcHBseShtX2N0X2Zyb3plbiwgMSwgc2NhbGUpKQpjb2xuYW1lcyhtX2N0X2Zyb3plbikgPSByb3duYW1lcyhtX2N0X2ZyZXNoKVstMl0KbV9jdF9mcmVzaCA9IGxvZyh0KG1fY3RfZnJlc2gpWywtMl0pCiNtX2N0X2ZyZXNoID0gdChhcHBseShtX2N0X2ZyZXNoLCAxLCBzY2FsZSkpCmNvbG5hbWVzKG1fY3RfZnJlc2gpID0gY29sbmFtZXMobV9jdF9mcm96ZW4pCgptZWFuX2N0ID0gbWVyZ2UobV9jdF9mcmVzaCwgbV9jdF9mcm96ZW4sIGJ5ID0gMCkKcm93bmFtZXMobWVhbl9jdCkgPSBtZWFuX2N0WywxXQptZWFuX2N0ID0gbWVhbl9jdFssLTFdCmNvbG5hbWVzKG1lYW5fY3QpID0gcGFzdGUwKHJlcChjb2xuYW1lcyhtX2N0X2ZyZXNoKSwgMiksIHJlcChjKCJfZnJlc2giLCAiX2Zyb3plbiIpLCBlYWNoID0gNSkpCgpwYXIobWZyb3cgPSBjKDIsMykpCnBsb3QobWVhbl9jdCRDaG9sYW5naW9jeXRlc19mcmVzaCwgbWVhbl9jdCRDaG9sYW5naW9jeXRlc19mcm96ZW4sIHBjaCA9IDIwLCBjZXggPSAwLjUsIHhsaW0gPSBjKC04LDUpLCB5bGltID0gYygtOCw1KSkKdGl0bGUoIkNob2xhbmdpb2N5dGVzIikKYWJsaW5lKDAsMSkKcGxvdChtZWFuX2N0JEVuZG90aGVsaWFsX2ZyZXNoLCBtZWFuX2N0JEVuZG90aGVsaWFsX2Zyb3plbiwgcGNoID0gMjAsIGNleCA9IDAuNSwgeGxpbSA9IGMoLTgsNSksIHlsaW0gPSBjKC04LDUpKQp0aXRsZSgiRW5kb3RoZWxpYWwiKQphYmxpbmUoMCwxKQpwbG90KG1lYW5fY3QkSGVwYXRvY3l0ZXNfZnJlc2gsIG1lYW5fY3QkSGVwYXRvY3l0ZXNfZnJvemVuLCBwY2ggPSAyMCwgY2V4ID0gMC41LCB4bGltID0gYygtMTAsNiksIHlsaW0gPSBjKC0xMCw2KSkKdGl0bGUoIkhlcGF0b2N5dGVzIikKYWJsaW5lKDAsMSkKcGxvdChtZWFuX2N0JEltbXVuZV9mcmVzaCwgbWVhbl9jdCRJbW11bmVfZnJvemVuLCBwY2ggPSAyMCwgY2V4ID0gMC41LCB4bGltID0gYygtOCw1KSwgeWxpbSA9IGMoLTgsNSkpCnRpdGxlKCJJbW11bmUiKQphYmxpbmUoMCwxKQpwbG90KG1lYW5fY3QkTWVzZW5jaHltYWxfZnJlc2gsIG1lYW5fY3QkTWVzZW5jaHltYWxfZnJvemVuLCBwY2ggPSAyMCwgY2V4ID0gMC41LCB4bGltID0gYygtOCw1KSwgeWxpbSA9IGMoLTgsNSkpCnRpdGxlKCJNZXNlbmNoeW1hbCIpCmFibGluZSgwLDEpCnBsb3Qocm93TWVhbnMobWVhbl9jdFssMTo1XSksIHJvd01lYW5zKG1lYW5fY3RbLDY6MTBdKSwgcGNoID0gMjAsIGNleCA9IDAuNSwgeGxpbSA9IGMoLTgsNSksIHlsaW0gPSBjKC04LDUpKQp0aXRsZSgiQWxsIikKYWJsaW5lKDAsMSkKYGBgCgoKIyMgU3VwcGxlbWVudGFyeQpVTUFQIHdpdGggaGVhbHRoeSBkb25vcnMgc3BsaXQKCmBgYHtyLCBmaWcuaGVpZ2h0PTIsIGZpZy53aWR0aD0zfQpwbG90X2RmID0gZGF0YS5mcmFtZShoY2VsbHNfY3NzQHJlZHVjdGlvbnMkdW1hcF9jc3NAY2VsbC5lbWJlZGRpbmdzKQpwbG90X2RmJERvbm9yID0gZmFjdG9yKGhjZWxsc19jc3NAbWV0YS5kYXRhJERvbm9yKQpwbG90X2RmJERvbm9yID0gcGx5cjo6cmV2YWx1ZShwbG90X2RmJERvbm9yLCBjKCJIRDEiID0gInNjX0gxIiwgIkhEMiIgPSAic2NfSDIiLCAiSEQzIiA9ICJzY19IMyIpKQoKcGx0ID0gZ2dwbG90KHBsb3RfZGZbc2FtcGxlKDE6bnJvdyhwbG90X2RmKSwgbnJvdyhwbG90X2RmKSwgcmVwbGFjZSA9IEYpLF0sIAogICAgICAgICAgICAgYWVzKHggPSBVTUFDU1NfMSwgeSA9IFVNQUNTU18yLCBjb2xvdXIgPSBEb25vcikpKwogIGZhY2V0X3dyYXAofkRvbm9yKSsKICBnZW9tX3BvaW50KHNpemUgPSAwLjE1KSsKICBndWlkZXMoY29sb3VyID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZSA9IDMpLCB0aXRsZSA9ICJEb25vcnMiKSkrCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjb2xkb24pKwogIHRoZW1lX2NsYXNzaWMoKSsKICB0aF9nZW4rCiAgdGhlbWUoYXhpcy5saW5lID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMCksCiAgICAgICAgYXNwZWN0LnJhdGlvID0gMSkKCnBkZigiZmlndXJlX3BhbmVscy9maWcxL3VtYXBfZnJlc2hfZG9ub3JzX3NwbGl0LnBkZiIsIAogICAgdXNlRGluZ2JhdHMgPSBGLCBoZWlnaHQgPSA0LCB3aWR0aCA9IDcpCnByaW50KHBsdCkKZGV2Lm9mZigpCnBuZygiZmlndXJlX3BhbmVscy9maWcxL3VtYXBfZnJlc2hfZG9ub3JzX3NwbGl0LnBuZyIsIAogICAgaGVpZ2h0PTgsIHdpZHRoPTEwLCB1bml0PSJjbSIsIHJlcz02MDAsIGFudGlhbGlhcyA9ICJzdWJwaXhlbCIpCnByaW50KHBsdCkKZGV2Lm9mZigpCnBkZigiZmlndXJlX3BhbmVscy9maWcxL3VtYXBfZnJlc2hfZG9ub3JzX25vTGVnX3NwbGl0LnBkZiIsIAogICAgdXNlRGluZ2JhdHMgPSBGLCBoZWlnaHQgPSA0LCB3aWR0aCA9IDcpCnByaW50KHBsdCt0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpKQpkZXYub2ZmKCkKcG5nKCJmaWd1cmVfcGFuZWxzL2ZpZzEvdW1hcF9mcmVzaF9kb25vcnNfbm9MZWdfc3BsaXQucG5nIiwgCiAgICBoZWlnaHQ9OCwgd2lkdGg9MTAsIHVuaXQ9ImNtIiwgcmVzPTYwMCwgYW50aWFsaWFzID0gInN1YnBpeGVsIikKcHJpbnQocGx0K3RoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikpCmRldi5vZmYoKQpgYGAKCkJveHBsb3Qgd2l0aCBuVU1JCgpgYGB7cn0KcGxvdF9kZiA9IGRhdGEuZnJhbWUoaGNlbGxzX2Nzc0ByZWR1Y3Rpb25zJHVtYXBfY3NzQGNlbGwuZW1iZWRkaW5ncykKcGxvdF9kZiRuYW1lc19tYWpvciA9IGFzLmNoYXJhY3RlcihoY2VsbHNfY3NzQG1ldGEuZGF0YSRuYW1lc19tYWpvcikKcGxvdF9kZiRuYW1lc19tYWpvcltwbG90X2RmJG5hbWVzX21ham9yPT0iVCBjZWxscyIgfCAKICAgICAgICAgICAgICAgICAgICAgIHBsb3RfZGYkbmFtZXNfbWFqb3I9PSJCIGNlbGxzIiB8IAogICAgICAgICAgICAgICAgICAgICAgcGxvdF9kZiRuYW1lc19tYWpvcj09Ik1hY3JvcGhhZ2VzIiB8CiAgICAgICAgICAgICAgICAgICAgICBwbG90X2RmJG5hbWVzX21ham9yPT0iRENzIl0gPSAiSW1tdW5lIgpwbG90X2RmJG5hbWVzX21ham9yW3Bsb3RfZGYkbmFtZXNfbWFqb3I9PSJTdGVsbGF0ZSBjZWxscyJdID0gIk1lc2VuY2h5bWFsIgpwbG90X2RmJG5hbWVzX21ham9yW3Bsb3RfZGYkbmFtZXNfbWFqb3I9PSJFbmRvdGhlbGlhbCBjZWxscyJdID0gIkVuZG90aGVsaWFsIgpwbG90X2RmJG5HZW5lID0gaGNlbGxzX2Nzc0BtZXRhLmRhdGEkbkZlYXR1cmVfU0NUCnBsb3RfZGYgPSBwbG90X2RmWywzOjVdCnNhdmVSRFMocGxvdF9kZiwgIi4vdG9fc2VuZC9kZl9jZWxsdHlwZXNfdW1pX2dlbmUuUkRTIikgIyBwbG90dGVkIGJ5IEFnYQpgYGAKClVNQVAgd2l0aCBhbGwgY2VsbCB0eXBlcwoKYGBge3J9CnBsb3RfZGYgPSBkYXRhLmZyYW1lKGhjZWxsc19jc3NAcmVkdWN0aW9ucyR1bWFwX2Nzc0BjZWxsLmVtYmVkZGluZ3MpCmNvbG5hbWVzKHBsb3RfZGYpID0gYygiVU1BUENTU18xIiwgIlVNQVBDU1NfMiIpCnBsb3RfZGYkbmFtZXNfbWFqb3IgPSBhcy5jaGFyYWN0ZXIoaGNlbGxzX2Nzc0BtZXRhLmRhdGEkbmFtZXNfbWFqb3IpCnBsb3RfZGYkbmFtZXNfbWFqb3JbcGxvdF9kZiRuYW1lc19tYWpvcj09IlQgY2VsbHMiIHwgCiAgICAgICAgICAgICAgICAgICAgICBwbG90X2RmJG5hbWVzX21ham9yPT0iQiBjZWxscyIgfCAKICAgICAgICAgICAgICAgICAgICAgIHBsb3RfZGYkbmFtZXNfbWFqb3I9PSJNYWNyb3BoYWdlcyIgfAogICAgICAgICAgICAgICAgICAgICAgcGxvdF9kZiRuYW1lc19tYWpvcj09IkRDcyJdID0gIkltbXVuZSIKcGxvdF9kZiRuYW1lc19tYWpvcltwbG90X2RmJG5hbWVzX21ham9yPT0iU3RlbGxhdGUgY2VsbHMiXSA9ICJNZXNlbmNoeW1hbCIKcGxvdF9kZiRuYW1lc19tYWpvcltwbG90X2RmJG5hbWVzX21ham9yPT0iRW5kb3RoZWxpYWwgY2VsbHMiXSA9ICJFbmRvdGhlbGlhbCIKcGxvdF9kZiRuYW1lc19jbHVzdGVycyA9IGFzLmNoYXJhY3RlcihoY2VsbHNfY3NzQG1ldGEuZGF0YSRuYW1lc19jbHVzdGVycykKcGxvdF9kZiRuYW1lc19jbHVzdGVyc1tncmVwbCgiSGVwYXRvY3l0ZXMgIiwgcGxvdF9kZiRuYW1lc19jbHVzdGVycyldID0gIkhlcGF0b2N5dGVzIgpwbG90X2RmJG5hbWVzX2NsdXN0ZXJzW2dyZXBsKCJjZW50cmFsIHZlaW4iLCBwbG90X2RmJG5hbWVzX2NsdXN0ZXJzKV0gPSAiTFNFQyBwZXJpY2VudHJhbCIKcGxvdF9kZiRuYW1lc19jbHVzdGVyc1tncmVwbCgicG9ydGFsIHZlaW4iLCBwbG90X2RmJG5hbWVzX2NsdXN0ZXJzKV0gPSAiTFNFQyBwZXJpcG9ydGFsIgpwbG90X2RmJG5hbWVzX2NsdXN0ZXJzW2dyZXBsKCJpbnRlcmFjdGlvbiIsIHBsb3RfZGYkbmFtZXNfY2x1c3RlcnMpIHwKICAgICAgICAgICAgICAgICAgICAgICAgIGdyZXBsKCJtaXgiLCBwbG90X2RmJG5hbWVzX2NsdXN0ZXJzKSBdID0gIkRvdWJsZXRzIgpwbG90X2RmJG5hbWVzX2NsdXN0ZXJzID0gZmFjdG9yKHBsb3RfZGYkbmFtZXNfY2x1c3RlcnMsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIkNob2xhbmdpb2N5dGVzIiwgIkxTRUMgcGVyaXBvcnRhbCIsICJMU0VDIHBlcmljZW50cmFsIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRW5kb3RoZWxpYWwgY2VsbHMgKG5vbi1MU0VDKSIsICJIZXBhdG9jeXRlcyIsICJLdXBmZmVyIGNlbGxzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJNYWNyb3BoYWdlcyIsICJjRENzIiwgInBEQ3MiLCAiYWItVCBjZWxscyIsICJnZC1UIGNlbGxzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJCIGNlbGxzIiwgIlBsYXNtYWJsYXN0cyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiU3RlbGxhdGUgY2VsbHMiLCAiRGl2aWRpbmcgY2VsbHMiLCAiRG91YmxldHMiKSkKCnBsdHVtYXAgPSBnZ3Bsb3QocGxvdF9kZiwgYWVzKHkgPSBVTUFQQ1NTXzIsIHggPSBVTUFQQ1NTXzEsIGNvbG91ciA9IG5hbWVzX2NsdXN0ZXJzKSkrCiAgZ2VvbV9wb2ludChzaXplID0gcG9pbnRzaXplKSsKICBsYWJzKGNvbG91ciA9ICJDZWxsIFR5cGUiKSsKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoY29sc2FsbGN0LCAiT3RoZXIiID0gImdyZXk4OCIpKSsKICBndWlkZXMoY29sb3VyID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZSA9IDIpKSkrCiAgdGhlbWUoYXNwZWN0LnJhdGlvID0gMSwKICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwKSwKICAgICAgICBheGlzLmxpbmUgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF9ibGFuaygpKQoKcGRmKCJmaWd1cmVfcGFuZWxzL2ZpZzEvdW1hcF9oX2FsbF9jZWxsdHlwZXMucGRmIiwgaGVpZ2h0ID0gNSwgd2lkdGggPSA2LCB1c2VEaW5nYmF0cyA9IEYpCnByaW50KHBsdHVtYXApCmRldi5vZmYoKQpwbmcoImZpZ3VyZV9wYW5lbHMvZmlnMS91bWFwX2hfYWxsX2NlbGx0eXBlcy5wbmciLCBoZWlnaHQgPSAzMjUsIHdpZHRoID0gNDAwLCBhbnRpYWxpYXMgPSAic3VicGl4ZWwiKQpwcmludChwbHR1bWFwKQpkZXYub2ZmKCkKCnBsb3RfZGYkbmFtZXNfY2x1c3RlcnNbcGxvdF9kZiRuYW1lc19tYWpvciE9IkltbXVuZSJdID0gIkRvdWJsZXRzIgpsZXZlbHMocGxvdF9kZiRuYW1lc19jbHVzdGVycylbbGV2ZWxzKHBsb3RfZGYkbmFtZXNfY2x1c3RlcnMpPT0iRG91YmxldHMiXSA9ICJPdGhlciIKcGx0dW1hcCA9IGdncGxvdChwbG90X2RmLCBhZXMoeSA9IFVNQVBDU1NfMiwgeCA9IFVNQVBDU1NfMSwgY29sb3VyID0gbmFtZXNfY2x1c3RlcnMpKSsKICBnZW9tX3BvaW50KHNpemUgPSBwb2ludHNpemUpKwogIGxhYnMoY29sb3VyID0gIkNlbGwgVHlwZSIpKwogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYyhjb2xzYWxsY3QsICJPdGhlciIgPSAiZ3JleTg4IikpKwogIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gMikpKSsKICB0aGVtZShhc3BlY3QucmF0aW8gPSAxLAogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDApLAogICAgICAgIGF4aXMubGluZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X2JsYW5rKCkpCmBgYAoKSGVhdG1hcCB3aXRoIG1hcmtlcnMgZm9yIGFsbCBjZWxsIHR5cGVzCgpgYGB7cn0KcGxvdF9kZiA9IGRhdGEuZnJhbWUoaGNlbGxzX2Nzc0ByZWR1Y3Rpb25zJHVtYXBfY3NzQGNlbGwuZW1iZWRkaW5ncykKY29sbmFtZXMocGxvdF9kZikgPSBjKCJVTUFQQ1NTXzEiLCAiVU1BUENTU18yIikKcGxvdF9kZiRuYW1lc19tYWpvciA9IGFzLmNoYXJhY3RlcihoY2VsbHNfY3NzQG1ldGEuZGF0YSRuYW1lc19tYWpvcikKcGxvdF9kZiRuYW1lc19tYWpvcltwbG90X2RmJG5hbWVzX21ham9yPT0iVCBjZWxscyIgfCAKICAgICAgICAgICAgICAgICAgICAgIHBsb3RfZGYkbmFtZXNfbWFqb3I9PSJCIGNlbGxzIiB8IAogICAgICAgICAgICAgICAgICAgICAgcGxvdF9kZiRuYW1lc19tYWpvcj09Ik1hY3JvcGhhZ2VzIiB8CiAgICAgICAgICAgICAgICAgICAgICBwbG90X2RmJG5hbWVzX21ham9yPT0iRENzIl0gPSAiSW1tdW5lIgpwbG90X2RmJG5hbWVzX21ham9yW3Bsb3RfZGYkbmFtZXNfbWFqb3I9PSJTdGVsbGF0ZSBjZWxscyJdID0gIk1lc2VuY2h5bWFsIgpwbG90X2RmJG5hbWVzX21ham9yW3Bsb3RfZGYkbmFtZXNfbWFqb3I9PSJFbmRvdGhlbGlhbCBjZWxscyJdID0gIkVuZG90aGVsaWFsIgpwbG90X2RmJG5hbWVzX2NsdXN0ZXJzID0gYXMuY2hhcmFjdGVyKGhjZWxsc19jc3NAbWV0YS5kYXRhJG5hbWVzX2NsdXN0ZXJzKQpwbG90X2RmJG5hbWVzX2NsdXN0ZXJzW2dyZXBsKCJIZXBhdG9jeXRlcyAiLCBwbG90X2RmJG5hbWVzX2NsdXN0ZXJzKV0gPSAiSGVwYXRvY3l0ZXMiCnBsb3RfZGYkbmFtZXNfY2x1c3RlcnNbZ3JlcGwoImNlbnRyYWwgdmVpbiIsIHBsb3RfZGYkbmFtZXNfY2x1c3RlcnMpXSA9ICJMU0VDIHBlcmljZW50cmFsIgpwbG90X2RmJG5hbWVzX2NsdXN0ZXJzW2dyZXBsKCJwb3J0YWwgdmVpbiIsIHBsb3RfZGYkbmFtZXNfY2x1c3RlcnMpXSA9ICJMU0VDIHBlcmlwb3J0YWwiCnBsb3RfZGYkbmFtZXNfY2x1c3RlcnNbZ3JlcGwoImludGVyYWN0aW9uIiwgcGxvdF9kZiRuYW1lc19jbHVzdGVycykgfAogICAgICAgICAgICAgICAgICAgICAgICAgZ3JlcGwoIm1peCIsIHBsb3RfZGYkbmFtZXNfY2x1c3RlcnMpIF0gPSAiRG91YmxldHMiCnBsb3RfZGYkbmFtZXNfY2x1c3RlcnMgPSBmYWN0b3IocGxvdF9kZiRuYW1lc19jbHVzdGVycywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygiQ2hvbGFuZ2lvY3l0ZXMiLCAiTFNFQyBwZXJpcG9ydGFsIiwgIkxTRUMgcGVyaWNlbnRyYWwiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJFbmRvdGhlbGlhbCBjZWxscyAobm9uLUxTRUMpIiwgIkhlcGF0b2N5dGVzIiwgIkt1cGZmZXIgY2VsbHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk1hY3JvcGhhZ2VzIiwgImNEQ3MiLCAicERDcyIsICJhYi1UIGNlbGxzIiwgImdkLVQgY2VsbHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkIgY2VsbHMiLCAiUGxhc21hYmxhc3RzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTdGVsbGF0ZSBjZWxscyIsICJEaXZpZGluZyBjZWxscyIsICJEb3VibGV0cyIpKQpwbG90X2RmID0gcGxvdF9kZltwbG90X2RmJG5hbWVzX2NsdXN0ZXJzIT0iRG91YmxldHMiLF0KCm5tZyA9IGMoIktSVDciLCAiQ0QyNCIsICAiTElMUkE0IiwgIklSRjciLCAgIkZDRVIxQSIsICJDTEVDMTBBIiwgICJDQ0wyMyIsIkNMRUMxQiIsICAiSU5NVCIsIlNFTFAiLCAgCiAgICAgICAgIk1BUkNPIiwiQ0Q1TCIsICAiQ1lQMkUxIiwiT1JNMiIsICAiTVM0QTEiLCJDRDc5QSIsICAiQ0xFQzE0QSIsIkVETlJCIiwgICJJR0xDMiIsIkNEMjciLCAgCiAgICAgICAgIlRSREMiLCJLTFJEMSIsICAiVFJBQyIsIkNEM0UiLCAgIkRDTiIsIkNPTEVDMTEiLCAgIlMxMDBBMTIiLCJDRDMwMEUiKQpubWcgPSBubWdbYygxLDIsMTMsMTQsMTcsMTgsNyw4LDksMTAsMjUsMjYsMjcsMjgsMTEsMTIsNSw2LDMsNCwyMywyNCwyMSwyMiwxNSwxNiwxOSwyMCldCgptMSA9IEdldEFzc2F5RGF0YShoY2VsbHNfY3NzLCBzbG90PSJkYXRhIilbbm1nLHJvd25hbWVzKHBsb3RfZGYpXQptX2N0X2ZyZXNoID0gYXBwbHkobTEsIDEsIGZ1bmN0aW9uKHgpIHRhcHBseSh4LCBhcy5jaGFyYWN0ZXIocGxvdF9kZiRuYW1lc19jbHVzdGVycyksIG1lYW4pKQptX2N0X2ZyZXNoW21fY3RfZnJlc2g+NF0gPSA0LjAxCm1fY3RfZnJlc2hbbV9jdF9mcmVzaDwoLTQpXSA9IC00LjAxCgphbm5vdF9kZiA9IHVuaXF1ZShwbG90X2RmWyxjKDMsNCldKQphbm5vdF9kZiA9IGRhdGEuZnJhbWUocm93Lm5hbWVzID0gYW5ub3RfZGYkbmFtZXNfY2x1c3RlcnMsICJjdCIgPSBhbm5vdF9kZiRuYW1lc19tYWpvcikKaGVhdCA9IHBoZWF0bWFwOjpwaGVhdG1hcChzY2FsZShtX2N0X2ZyZXNoW2MoNCw3LDEwLDksNSwxNCwxMSw4LDMsMTIsMSw2LDIsMTMpLF0pLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBjbHVzdGVyaW5nX21ldGhvZCA9ICJ3YXJkLkQyIiwgdHJlZWhlaWdodF9yb3cgPSAwLAogICAgICAgICAgICAgICAgICAgICAgICAgIHRyZWVoZWlnaHRfY29sID0gMjAsIGZvbnRzaXplX3JvdyA9IDgsIGZvbnRzaXplX2NvbCA9IDgsCiAgICAgICAgICAgICAgICAgICAgICAgICAgY2x1c3Rlcl9jb2xzID0gRiwgY2x1c3Rlcl9yb3dzID0gRiwKICAgICAgICAgICAgICAgICAgICAgICAgICBhbm5vdGF0aW9uX3JvdyA9IGFubm90X2RmLCBhbm5vdGF0aW9uX2NvbG9ycyA9IGxpc3QoY3QgPSBjb2xzbWFqb3JbLTZdKSwKICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9IGNvbG9yUmFtcFBhbGV0dGUocmV2KGJyZXdlci5wYWwobiA9IDksIG5hbWUgPSAiUmRCdSIpKSkoMTAwKSkKCnBkZigiZmlndXJlX3BhbmVscy9maWcxL2hlYXRtYXBfYWxsX2NlbGx0eXBlcy5wZGYiLCBoZWlnaHQgPSAzLjUsIHdpZHRoID0gNywgdXNlRGluZ2JhdHMgPSBGKQpwcmludChoZWF0KQpkZXYub2ZmKCkKYGBgCgoKIyBGaWd1cmUgMgojIyBNYWluIEZpZ3VyZQpVTUFQIHdpdGggY2VsbCB0eXBlcwoKYGBge3J9CmFsbGNlbGxzX2NzcyA9IHJlYWRSRFMoZmlsZSA9ICJkYXRhL3Byb2Nlc3NlZC9hbGxjZWxsc19jc3NfcmVhbm5vdC5SRFMiKQoKbG9hZChmaWxlID0gImRhdGEvcHJvY2Vzc2VkL2hlYWx0aHlfc3JhdF9iZWZvcmVGaWx0ZXJpbmcuUkRhdGEiKQpsb2FkKGZpbGUgPSAiZGF0YS9wcm9jZXNzZWQvY29uZF9zcmF0X2JlZm9yZUZpbHRlcmluZy5SRGF0YSIpCmBgYAoKYGBge3J9CnBsb3RfZGYgPSBhbGxjZWxsc19jc3NAbWV0YS5kYXRhCnBsb3RfZGYgPSBjYmluZChwbG90X2RmLCBhbGxjZWxsc19jc3NAcmVkdWN0aW9ucyR1bWFwX2Nzc0BjZWxsLmVtYmVkZGluZ3MpCnBsb3RfZGYkQ29uZGl0aW9uID0gZmFjdG9yKHBsb3RfZGYkQ29uZGl0aW9uLCBsZXZlbHMgPSBjKCJoZWFsdGh5IiwgImVtYm9saXNlZCIsICJyZWdlbmVyYXRpbmciKSkKcGxvdF9kZiRtYWpvcl9jdFtpcy5uYShwbG90X2RmJG1ham9yX2N0KV0gPSBwbG90X2RmJGFsbGNlbGxzX21ham9yW2lzLm5hKHBsb3RfZGYkbWFqb3JfY3QpXQpwbG90X2RmJG1ham9yX2N0W3Bsb3RfZGYkbWFqb3JfY3Q9PSJEaXZpZGluZyBjZWxscyJdID0gIkltbXVuZSIgIyB0aGUgZGV0ZWN0ZWQgZGl2aWRpbmcgY2VsbHMgYXJlIG1vc3RseSAoaWYgbm90IGFsbCkgaW1tdW5lIApwbG90X2RmJG1ham9yX2N0ID0gZmFjdG9yKHBsb3RfZGYkbWFqb3JfY3QsIGxldmVscyA9IGMoIkhlcGF0b2N5dGVzIiwgIkVuZG90aGVsaWFsIiwgIkNob2xhbmdpb2N5dGVzIiwgIkltbXVuZSIsICJNZXNlbmNoeW1hbCIsICJEb3VibGV0cyIpKQoKcGx0dW1hcCA9IGdncGxvdChwbG90X2RmLCBhZXMoeSA9IFVNQVBDU1NfMiwgeCA9IFVNQVBDU1NfMSwgY29sb3VyID0gbWFqb3JfY3QpKSsKICBnZW9tX3BvaW50KHNpemUgPSBwb2ludHNpemUpKwogIGxhYnMoY29sb3VyID0gIkNlbGwgVHlwZSIpKwogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYyhjb2xzbWFqb3IsICJEb3VibGV0cyIgPSAiZ3JleTkwIikpKwogIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gMikpKSsKICB0aGVtZShhc3BlY3QucmF0aW8gPSAxLAogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDApLAogICAgICAgIGF4aXMubGluZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X2JsYW5rKCkpCgpwZGYoImZpZ3VyZV9wYW5lbHMvZmlnMi91bWFwX21ham9yX2NlbGx0eXBlcy5wZGYiLCBoZWlnaHQgPSA1LCB3aWR0aCA9IDYsIHVzZURpbmdiYXRzID0gRikKcHJpbnQocGx0dW1hcCkKZGV2Lm9mZigpCnBuZygiZmlndXJlX3BhbmVscy9maWcyL3VtYXBfbWFqb3JfY2VsbHR5cGVzLnBuZyIsIGhlaWdodCA9IDMyNSwgd2lkdGggPSA0MDAsIGFudGlhbGlhcyA9ICJzdWJwaXhlbCIpCnByaW50KHBsdHVtYXApCmRldi5vZmYoKQpgYGAKClVNQVAgd2l0aCBhbGwgY2VsbCB0eXBlcwoKYGBge3J9CnBsb3RfZGYgPSBhbGxjZWxsc19jc3NAbWV0YS5kYXRhCnBsb3RfZGYgPSBjYmluZChwbG90X2RmLCBhbGxjZWxsc19jc3NAcmVkdWN0aW9ucyR1bWFwX2Nzc0BjZWxsLmVtYmVkZGluZ3MpCnBsb3RfZGYkQ29uZGl0aW9uID0gZmFjdG9yKHBsb3RfZGYkQ29uZGl0aW9uLCBsZXZlbHMgPSBjKCJoZWFsdGh5IiwgImVtYm9saXNlZCIsICJyZWdlbmVyYXRpbmciKSkKcGxvdF9kZiRhbGxjZWxsc19zaW1wW2dyZXBsKCJpbnRlcmFjdGlvbiIsIHBsb3RfZGYkYWxsY2VsbHNfc2ltcCldID0gIkRvdWJsZXRzIgpwbG90X2RmJGFsbGNlbGxzX3NpbXBbZ3JlcGwoIkhlcGF0b2N5dGVzICIsIHBsb3RfZGYkYWxsY2VsbHNfc2ltcCldID0gIkhlcGF0b2N5dGVzIgpwbG90X2RmJGFsbGNlbGxzX3NpbXAgPSBmYWN0b3IocGxvdF9kZiRhbGxjZWxsc19zaW1wLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIkNob2xhbmdpb2N5dGVzIiwgIkxTRUMgcGVyaXBvcnRhbCIsICJMU0VDIHBlcmljZW50cmFsIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJFbmRvdGhlbGlhbCBjZWxscyAobm9uLUxTRUMpIiwgIkhlcGF0b2N5dGVzIiwgIkt1cGZmZXIgY2VsbHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTWFjcm9waGFnZXMiLCAiY0RDcyIsICJwRENzIiwgImFiLVQgY2VsbHMiLCAiZ2QtVCBjZWxscyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJCIGNlbGxzIiwgIlBsYXNtYWJsYXN0cyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTdGVsbGF0ZSBjZWxscyIsICJEaXZpZGluZyBjZWxscyIsICJEb3VibGV0cyIpKQoKcGx0dW1hcCA9IGdncGxvdChwbG90X2RmLCBhZXMoeSA9IFVNQVBDU1NfMiwgeCA9IFVNQVBDU1NfMSwgY29sb3VyID0gYWxsY2VsbHNfc2ltcCkpKwogIGdlb21fcG9pbnQoc2l6ZSA9IHBvaW50c2l6ZSkrCiAgbGFicyhjb2xvdXIgPSAiQ2VsbCBUeXBlIikrCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjb2xzYWxsY3QpKwogIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gMikpKSsKICB0aGVtZShhc3BlY3QucmF0aW8gPSAxLAogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDApLAogICAgICAgIGF4aXMubGluZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X2JsYW5rKCkpCgpwZGYoImZpZ3VyZV9wYW5lbHMvZmlnMi91bWFwX2FsbF9jZWxsdHlwZXMucGRmIiwgaGVpZ2h0ID0gNSwgd2lkdGggPSA2LCB1c2VEaW5nYmF0cyA9IEYpCnByaW50KHBsdHVtYXApCmRldi5vZmYoKQpwbmcoImZpZ3VyZV9wYW5lbHMvZmlnMi91bWFwX2FsbF9jZWxsdHlwZXMucG5nIiwgaGVpZ2h0ID0gMzI1LCB3aWR0aCA9IDQwMCwgYW50aWFsaWFzID0gInN1YnBpeGVsIikKcHJpbnQocGx0dW1hcCkKZGV2Lm9mZigpCmBgYAoKUHJvcG9ydGlvbiBvZiBlYWNoIGNlbGwgdHlwZSBwZXIgY29uZGl0aW9uCgpgYGB7cn0KZGZfY250ID0gdGFibGUocGxvdF9kZiRhbGxjZWxsc19zaW1wLCBwbG90X2RmJENvbmRpdGlvbilbLWMoMTUsMTYpLF0KZGZfY250X2hlcCA9IHJlc2hhcGUyOjptZWx0KGFwcGx5KGRmX2NudCwgMiwgZnVuY3Rpb24oeCkgcm91bmQoeC9zdW0oeCkqMTAwLCAxKSlbNSxdKQpkZl9jbnRfbm9oZXAgPSByZXNoYXBlMjo6bWVsdChhcHBseShkZl9jbnRbLTUsXSwgMiwgZnVuY3Rpb24oeCkgcm91bmQoeC9zdW0oeCkqMTAwLCAxKSkpCgpkZl9jbnRfYWxsID0gcmJpbmQoZGF0YS5mcmFtZSgiVmFyMSIgPSAiSGVwYXRvY3l0ZXMiLCAiVmFyMiIgPSByb3duYW1lcyhkZl9jbnRfaGVwKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJ2YWx1ZSIgPSBkZl9jbnRfaGVwJHZhbHVlKSwKICAgICAgICAgICAgICAgICAgIGRmX2NudF9ub2hlcCkKCm1hdF9jbnRfYWxsID0gcmVzaGFwZTI6OmRjYXN0KGRhdGEgPSBkZl9jbnRfYWxsLCBmb3JtdWxhID0gVmFyMSB+IFZhcjIsIHZhbHVlLnZhciA9ICJ2YWx1ZSIpCnJvd25hbWVzKG1hdF9jbnRfYWxsKSA9IG1hdF9jbnRfYWxsJFZhcjEKbWF0X2NudF9hbGwgPSBtYXRfY250X2FsbFssLTFdCmN0b3JkID0gaGNsdXN0KGRpc3QobWF0X2NudF9hbGxbLGMoMiwxLDMpXSkpJG9yZGVyCmN0b3JkID0gYyg3LCA0LCAxMCwgOSwgNSwgMTQsIDExLCA4LCAzLCAxMiwxLDYsMiwxMykKCmFubm90X2RmID0gdW5pcXVlKHBsb3RfZGZbLGMoIm1ham9yX2N0IiwiYWxsY2VsbHNfc2ltcCIpXSkKYW5ub3RfZGYgPSBkYXRhLmZyYW1lKHJvdy5uYW1lcyA9IGFubm90X2RmJGFsbGNlbGxzX3NpbXAsICJjdCIgPSBhbm5vdF9kZiRtYWpvcl9jdCkKaGVhdHAgPSBwaGVhdG1hcDo6cGhlYXRtYXAobWF0X2NudF9hbGxbY3RvcmQsYygyLDEsMyldLCBjbHVzdGVyX2NvbHMgPSBGLCBjbHVzdGVyX3Jvd3MgPSBGLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgdHJlZWhlaWdodF9yb3cgPSBGLCBkaXNwbGF5X251bWJlcnMgPSBULCBnYXBzX3JvdyA9IGMoMSwxKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIG51bWJlcl9jb2xvciA9IGMoImJsYWNrIiwgIndoaXRlIilbYXMuaW50ZWdlcihtYXRfY250X2FsbFtjdG9yZCxjKDIsMSwzKV0+NTApKzFdLAogICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9IGNvbG9yUmFtcFBhbGV0dGUoYnJld2VyLnBhbChuID0gOSwgbmFtZSA9ICJCbHVlcyIpKSgxMDApLAogICAgICAgICAgICAgICAgICAgICAgICAgICBmb250c2l6ZV9yb3cgPSA4LCBmb250c2l6ZV9jb2wgPSA4LAogICAgICAgICAgICAgICAgICAgICAgICAgICBhbm5vdGF0aW9uX3JvdyA9IGFubm90X2RmLCBhbm5vdGF0aW9uX2NvbG9ycyA9IGxpc3QoY3QgPSBjb2xzbWFqb3JbLTZdKSkKCnBkZigiZmlndXJlX3BhbmVscy9maWcyL2hlYXRtYXBfYWxsX2NlbGx0eXBlc19wcm9wLnBkZiIsIGhlaWdodCA9IDMuNSwgd2lkdGggPSA1LCB1c2VEaW5nYmF0cyA9IEYpCnByaW50KGhlYXRwKQpkZXYub2ZmKCkKYGBgCgpVTUFQIHdpdGggY29uZGl0aW9ucwoKYGBge3J9CnJhbmRvbXJvd3MgPSBzYW1wbGUoMTpucm93KHBsb3RfZGYpLCBzaXplID0gbnJvdyhwbG90X2RmKSwgcmVwbGFjZSA9IEYpCnBsdHVtYXBjb25kID0gZ2dwbG90KHBsb3RfZGZbcmFuZG9tcm93cyxdLCBhZXMoeSA9IFVNQVBDU1NfMiwgeCA9IFVNQVBDU1NfMSwgY29sb3VyID0gQ29uZGl0aW9uKSkrCiAgZ2VvbV9wb2ludChzaXplID0gcG9pbnRzaXplKSsKICBsYWJzKGNvbG91ciA9ICJDb25kaXRpb24iKSsKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGNvbGNvbmQpKwogIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gMikpKSsKICB0aGVtZShhc3BlY3QucmF0aW8gPSAxLAogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDApLAogICAgICAgIGF4aXMubGluZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X2JsYW5rKCkpCgpwZGYoImZpZ3VyZV9wYW5lbHMvZmlnMi91bWFwX2NvbmRpdGlvbi5wZGYiLCBoZWlnaHQgPSA1LCB3aWR0aCA9IDYsIHVzZURpbmdiYXRzID0gRikKcHJpbnQocGx0dW1hcGNvbmQpCmRldi5vZmYoKQpwbmcoImZpZ3VyZV9wYW5lbHMvZmlnMi91bWFwX2NvbmRpdGlvbi5wbmciLCBoZWlnaHQgPSAzMjUsIHdpZHRoID0gNDAwLCBhbnRpYWxpYXMgPSAic3VicGl4ZWwiKQpwcmludChwbHR1bWFwY29uZCkKZGV2Lm9mZigpCmBgYAoKVG9wIEdPIHRlcm1zIGFuZCBsb2FkIGRhdGEKCmBgYHtyfQojIGxvYWRpbmcgYW5kIHByZXBhcmluZyBkYXRhCmdvX2Vucl9saXN0ID0gcmVhZFJEUyhmaWxlID0gInJlc3VsdHMvY29uZF9lZmZlY3QvZ29fZW5yX2xpc3QuUkRTIikKCmdvX2Vucl9tYWpvciA9IGdvX2Vucl9saXN0JG1ham9yX2N0CmZvcihjYyBpbiBuYW1lcyhnb19lbnJfbWFqb3IpKXsgIyBhZGRpbmcgdGhlIHRlcm1zIGZvciBzdWJzYW1wbGVkIGhlcGF0b2N5dGVzCiAgZm9yKGN0IGluIG5hbWVzKGdvX2Vucl9tYWpvcltbY2NdXSkpewogICAgaWYoY3Q9PSJIZXBhdG9jeXRlcyIpewogICAgICBnb19lbnJfbWFqb3JbW2NjXV1bW2N0XV0gPSBnb19lbnJfbGlzdCRtYWpvcl9jdF9oZXBbW2NjXV0kSGVwYXRvY3l0ZXMKICAgIH0KICAgIGdvX2Vucl9tYWpvcltbY2NdXVtbY3RdXSA9IGdvX2Vucl9tYWpvcltbY2NdXVtbY3RdXVtnb19lbnJfbWFqb3JbW2NjXV1bW2N0XV0kREI9PSJHTyBUZXJtIixdCiAgfQp9CgoKZm9yKGNvbXAgaW4gbmFtZXMoZ29fZW5yX21ham9yKSl7CiAgZm9yKGN0IGluIG5hbWVzKGdvX2Vucl9tYWpvcltbY29tcF1dKSl7CiAgICBzdWJkaXIgPSAiZmlndXJlX3BhbmVscy9maWcyL2dvdGVybXNfY29uZF9mdWxsLyIKICAgIGdvX2Vucl9tYWpvcltbY29tcF1dW1tjdF1dJGdlbmVJRCA9IHVubGlzdChnb19lbnJfbWFqb3JbW2NvbXBdXVtbY3RdXSRnZW5lSUQpCiAgICB3cml0ZS50YWJsZShnb19lbnJfbWFqb3JbW2NvbXBdXVtbY3RdXSwgCiAgICAgICAgICAgICAgICBmaWxlID0gcGFzdGUwKHN1YmRpciwgIkdPVGVybUJQXyIsIGNvbXAsICJfIiwgY3QsICIuY3N2IiksIAogICAgICAgICAgICAgICAgY29sLm5hbWVzID0gVCwgcm93Lm5hbWVzID0gRiwgcXVvdGUgPSBGLCBzZXAgPSAiLCIpCiAgfQp9CmBgYAoKUGxvdHRpbmcgR08gVGVybXMgbWl4ZWQgYmV0d2VlbiBjb25kaXRpb25zCgpgYGB7cn0KdGVybXNfbGlzdCA9IGxpc3QoKQpmb3IoY3QgaW4gdW5pcXVlKG5hbWVzKGdvX2Vucl9tYWpvciRoZWFsdGh5X3ZfZW1ib2xpc2VkKSkpewogIGVtYl90ZXJtcyA9IGdvX2Vucl9tYWpvciRoZWFsdGh5X3ZfZW1ib2xpc2VkW1tjdF1dWyxjKDIsNyw4LDExKV0KICBlbWJfdGVybXMgPSBlbWJfdGVybXNbZW1iX3Rlcm1zJGNvbmQhPSJoZWFsdGh5IixdCiAgcmVnX3Rlcm1zID0gZ29fZW5yX21ham9yJGhlYWx0aHlfdl9yZWdlbmVyYXRpbmdbW2N0XV1bLGMoMiw3LDgsMTEpXQogIHJlZ190ZXJtcyA9IHJlZ190ZXJtc1tyZWdfdGVybXMkY29uZCE9ImhlYWx0aHkiLF0KICBib3RoX3Rlcm1zID0gbWVyZ2UoZW1iX3Rlcm1zLCByZWdfdGVybXMsIGJ5ID0gMSwgYWxsID0gVClbLC1jKDQsNyldCiAgY29sbmFtZXMoYm90aF90ZXJtcylbMjo1XSA9IGMoInF2YWxfZW1ib2xpemVkIiwgImdlbmVzX2VtYm9saXplZCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJxdmFsX3JlZ2VuZXJhdGluZyIsICJnZW5lc19yZWdlbmVyYXRpbmciKQogIGJvdGhfdGVybXMkcXZhbF9lbWJvbGl6ZWRbaXMubmEoYm90aF90ZXJtcyRxdmFsX2VtYm9saXplZCldID0gMQogIGJvdGhfdGVybXMkcXZhbF9yZWdlbmVyYXRpbmdbaXMubmEoYm90aF90ZXJtcyRxdmFsX3JlZ2VuZXJhdGluZyldID0gMQogIGJvdGhfdGVybXMkZ2VuZXNfZW1ib2xpemVkW2lzLm5hKGJvdGhfdGVybXMkZ2VuZXNfZW1ib2xpemVkKV0gPSAiIgogIGJvdGhfdGVybXMkZ2VuZXNfcmVnZW5lcmF0aW5nW2lzLm5hKGJvdGhfdGVybXMkZ2VuZXNfcmVnZW5lcmF0aW5nKV0gPSAiIgogIAogIGJvdGhfdGVybXMkZ2VuZXNfYWxsID0gdW5saXN0KGxhcHBseShzdHJzcGxpdChwYXN0ZTAoYm90aF90ZXJtcyRnZW5lc19lbWJvbGl6ZWQsICIvIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJvdGhfdGVybXMkZ2VuZXNfcmVnZW5lcmF0aW5nKSwiLyIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24oeCkgcGFzdGUwKHVuaXF1ZSh4W3ghPSIiXSksIGNvbGxhcHNlID0gIi8iKSkpCiAgCiAgYm90aF90ZXJtcyA9IGJvdGhfdGVybXNbYm90aF90ZXJtcyRxdmFsX2VtYm9saXplZDw9MC4wNSB8IGJvdGhfdGVybXMkcXZhbF9yZWdlbmVyYXRpbmc8PTAuMDUsXQogIAogIGJvdGhfdGVybXNfdG9wID0gZ2V0VG9wVGVybXNQYWlyZWQoYm90aF90ZXJtcywgbmNsID0gMTIsIG50ID0gMSkKICB0ZXJtc19saXN0W1tjdF1dID0gYm90aF90ZXJtc190b3AKfQoKcGx0X2xpc3QgPSBsaXN0KCkKZm9yKGN0IGluIG5hbWVzKHRlcm1zX2xpc3QpKXsKICBzdW1fZGYgPSB0ZXJtc19saXN0W1tjdF1dWyxjKDE6Myw3KV0KICBzdW1fZGYkRGVzY3JpcHRpb24gPSBicmVha1N0cihhcy5jaGFyYWN0ZXIoc3VtX2RmJERlc2NyaXB0aW9uKSwgbiA9IDMwKQogIHN1bV9kZiRxdmFsX21heFtzdW1fZGYkcXZhbF9lbWJvbGl6ZWQ+c3VtX2RmJHF2YWxfcmVnZW5lcmF0aW5nXSA9IDEtc3VtX2RmJHF2YWxfbWF4W3N1bV9kZiRxdmFsX2VtYm9saXplZD5zdW1fZGYkcXZhbF9yZWdlbmVyYXRpbmddCiAgcGxvdF9kZiA9IHJlc2hhcGUyOjptZWx0KHN1bV9kZlssMTozXSkKICBwbG90X2RmJERlc2NyaXB0aW9uID0gZmFjdG9yKHBsb3RfZGYkRGVzY3JpcHRpb24sIGxldmVscyA9IHN1bV9kZiREZXNjcmlwdGlvbltvcmRlcihzdW1fZGYkcXZhbF9tYXgpXSkKICBwbG90X2RmJHZhcmlhYmxlID0gdW5saXN0KGxhcHBseShzdHJzcGxpdChhcy5jaGFyYWN0ZXIocGxvdF9kZiR2YXJpYWJsZSksICJfIiksIGZ1bmN0aW9uKHgpIHhbMl0pKQogIAogIHBsdF9saXN0W1tjdF1dID0gZ2dwbG90KHBsb3RfZGYsIGFlcyh4ID0gLWxvZzEwKHZhbHVlKSwgeSA9IERlc2NyaXB0aW9uLCBmaWxsID0gdmFyaWFibGUpKSsKICAgIGdlb21fY29sKHBvc2l0aW9uID0gImRvZGdlIikrCiAgICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAtbG9nMTAoMC4wNSksIGxpbmV0eXBlID0gImRhc2hlZCIpKwogICAgc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cyA9IGMoMCwgbWF4KC1sb2cxMChwbG90X2RmJHZhbHVlKSswLjMpKSwgZXhwYW5kID0gYygwLDApKSsKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNvbGNvbmQpKwogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICAgICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfbGluZSgpKQp9Cgpmb3IobiBpbiBuYW1lcyhwbHRfbGlzdCkpewogIHBkZihwYXN0ZTAoImZpZ3VyZV9wYW5lbHMvZmlnMi9nb3Rlcm1zX2NvbmQvZ290ZXJtc19taXhlZEdPXyIsIG4sICIucGRmIiksIAogICAgICBoZWlnaHQgPSAyLjgsIHdpZHRoID0gMykKICBwcmludChwbHRfbGlzdFtbbl1dKQogIGRldi5vZmYoKQp9Cgpjb3dwbG90OjpwbG90X2dyaWQocGxvdGxpc3QgPSBwbHRfbGlzdCwgbmNvbCA9IDQsIGFsaWduID0gImh2IikKYGBgCgpUb3AgZW5yaWNoZWQgR08gVGVybXMgLSBncm91cCBzaW1pbGFyIHRlcm1zIGFuZCByZXBvcnQgdGhlIHRvcCAxIG9mIGVhY2ggb2YgNSBncm91cHMgZGV0ZWN0ZWQKCmBgYHtyfQpnb3BsdCA9IGxpc3QoKQpnb3RhYiA9IGxpc3QoKQpmb3IoY29tcCBpbiBuYW1lcyhnb19lbnJfbWFqb3IpKXsKICBmb3IoZ3IgaW4gbmFtZXMoZ29fZW5yX21ham9yW1tjb21wXV0pKXsKICAgIGNvbmRzID0gc3Ryc3BsaXQoY29tcCwgIl92XyIpW1sxXV0KICAgIGZvcihjYyBpbiBjb25kcyl7CiAgICAgIHN1Yl9kZiA9IGdvX2Vucl9tYWpvcltbY29tcF1dW1tncl1dW2dvX2Vucl9tYWpvcltbY29tcF1dW1tncl1dJERCPT0iR08gVGVybSIgJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdvX2Vucl9tYWpvcltbY29tcF1dW1tncl1dJHF2YWx1ZTw9MC4wNSAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ29fZW5yX21ham9yW1tjb21wXV1bW2dyXV0kY29uZD09Y2MsXQogICAgICBpZihucm93KHN1Yl9kZik+MCl7CiAgICAgICAgc3ViX2RmID0gZ2V0VG9wVGVybXMoc3ViX2RmLCBuY2wgPSA1LCBudCA9IDEpCiAgICAgICAgc3ViX2RmID0gc3ViX2RmW29yZGVyKHN1Yl9kZiRxdmFsdWUsIGRlY3JlYXNpbmcgPSBGKSxdCiAgICAgICAgbCA9IGlmZWxzZShucm93KHN1Yl9kZik+MTAsIDEwLCBucm93KHN1Yl9kZikpCiAgICAgICAgc3ViX2RmID0gc3ViX2RmWzE6bCxdCiAgICAgICAgc3ViX2RmJGdlbmVJRCA9IHVubGlzdChzdWJfZGYkZ2VuZUlEKQogICAgICAgIHN1Yl9kZiREZXNjcmlwdGlvbiA9IGJyZWFrU3RyKGFzLmNoYXJhY3RlcihzdWJfZGYkRGVzY3JpcHRpb24pLCAzMCkKICAgICAgICBzdWJfZGYkRGVzY3JpcHRpb24gPSBmYWN0b3Ioc3ViX2RmJERlc2NyaXB0aW9uLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gcmV2KGFzLmNoYXJhY3RlcihzdWJfZGYkRGVzY3JpcHRpb24pKSkKICAgICAgICAKICAgICAgICBnb3BsdFtbcGFzdGUwKGNvbXAsICJfXyIsIGdyLCAiX18iLCBjYyldXSA9IGdncGxvdChzdWJfZGYsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFlcyh4ID0gLWxvZzEwKHF2YWx1ZSksIHkgPSBEZXNjcmlwdGlvbikpKwogICAgICAgICAgZ2VvbV9jb2woKSsKICAgICAgICAgIHNjYWxlX3hfY29udGludW91cyhleHBhbmQgPSBjKDAsMCksIGxpbWl0cyA9IGMoMCwgbWF4KC1sb2cxMChzdWJfZGYkcXZhbHVlKSkrMC4yNSkpKwogICAgICAgICAgbGFicyh5ID0gIkdPIFRlcm0gRGVzY3JpcHRpb24iLCB0aXRsZSA9IHBhc3RlMChjYywgIiB2cyAiLCBjb25kc1tjb25kcyE9Y2NdKSkrCiAgICAgICAgICB0aGVtZShheGlzLnRpY2tzLnggPSBlbGVtZW50X2xpbmUoKSwKICAgICAgICAgICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMSwgdmp1c3QgPSAwLjUsIGxpbmVoZWlnaHQgPSAwLjc1LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDcpLAogICAgICAgICAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTAsIGhqdXN0ID0gMCksCiAgICAgICAgICAgICAgICBwbG90LnRpdGxlLnBvc2l0aW9uID0gInBsb3QiKQogICAgICAgIGdvdGFiW1twYXN0ZTAoY29tcCwgIl9fIiwgZ3IsICJfXyIsIGNjKV1dID0gc3ViX2RmCiAgICAgIH0KICAgIH0KICB9Cn0KZm9yKG4gaW4gbmFtZXMoZ29wbHQpKXsKICBwZGYocGFzdGUwKCJmaWd1cmVfcGFuZWxzL2ZpZzIvZ290ZXJtc19jb25kL2dvdGVybXNfZmlsdEdPXyIsIG4sICIucGRmIiksIAogICAgICBoZWlnaHQgPSAyLCB3aWR0aCA9IDMpCiAgcHJpbnQoZ29wbHRbW25dXSkKICBkZXYub2ZmKCkKICAKICB3cml0ZS5jc3YoZ290YWJbW25dXSwgZmlsZSA9IHBhc3RlMCgiZmlndXJlX3BhbmVscy9maWcyL2dvdGVybXNfY29uZC9nb3Rlcm1zX2ZpbHRHT18iLCBuLCAiLmNzdiIpLAogICAgICAgICAgICByb3cubmFtZXMgPSBGLCBxdW90ZSA9IEYpCn0KYGBgCgpERSBiZXR3ZWVuIGNvbmRpdGlvbnMgZm9yIGNlbGwgdHlwZXMKCmBgYHtyfQpmaWx0X2NvbXBzID0gcmVhZFJEUyhmaWxlID0gInJlc3VsdHMvY29uZF9lZmZlY3QvYWxsX2ZpbHRfY29uZF9jb21wcy5SRFMiKQoKZm9yKGNvbXAgaW4gbmFtZXMoZmlsdF9jb21wcyRtYWpvcl9jdCkpewogIHN1YmRpciA9ICJmaWd1cmVfcGFuZWxzL2ZpZzIvREVfdGFibGVzLyIKICBkZV9kZiA9IGZpbHRfY29tcHMkbWFqb3JfY3RbW2NvbXBdXQogIGRlX2RmID0gZGVfZGZbZGVfZGYkY2VsbHR5cGUhPSJIZXBhdG9jeXRlcyIsXQogIGRlX2RmID0gcmJpbmQoZGVfZGYsIGZpbHRfY29tcHMkbWFqb3JfY3RfaGVwW1tjb21wXV0pCiAgZGVfZGYgPSBkZV9kZltkZV9kZiRwX3ZhbF9hZGo8PTAuMDUsXQogIAogIHdyaXRlLmNzdihkZV9kZltvcmRlcihkZV9kZiRhdmdfbG9nRkMsIGRlY3JlYXNpbmcgPSBUKSxdLCAKICAgICAgICAgICAgZmlsZSA9IHBhc3RlMChzdWJkaXIsICJERWNvbmRfbWFqb3JfY3RfIiwgY29tcCwgIi5jc3YiKSwgCiAgICAgICAgICAgIGNvbC5uYW1lcyA9IFQsIHJvdy5uYW1lcyA9IEYsIHF1b3RlID0gRikKfQoKZm9yKGcgaW4gbmFtZXMoZmlsdF9jb21wcykpewogIGZvcihjb21wIGluIG5hbWVzKGZpbHRfY29tcHNbW2ddXSkpewogICAgc3ViZGlyID0gZmlsZS5wYXRoKCJ0b19zZW5kIiwgZykKICAgIHdyaXRlLmNzdihmaWx0X2NvbXBzW1tnXV1bW2NvbXBdXSwgZmlsZSA9IHBhc3RlMChzdWJkaXIsICIvREVjb25kaXRpb25zXyIsIGNvbXAsICJfIiwgZywgIi5jc3YiKSwgCiAgICAgICAgICAgICAgY29sLm5hbWVzID0gVCwgcm93Lm5hbWVzID0gRiwgcXVvdGUgPSBGKQogIH0KfQpgYGAKCk1ham9yIGNlbGwgdHlwZXMKCmBgYHtyfQpnZW5lc190b19wbG90ID0gbGlzdCgiSGVwYXRvY3l0ZXMiID0gYygiSEFNUCIsICJTQUExIiwgIkZHQSIsICJHMFMyIiwgIlRORlJTRjFBIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNZUDNBNyIsICJNVDFBIiwgIkREWDIxIiwgIklMMVJBUCIsICJNVDFYIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk1HTEwiLCAiTUZTRDJBIiwgIkFQT0E0IiwgIklSRjciLCAiQ0VCUEEiKSwgCiAgICAgICAgICAgICAgICAgICAgICAiSW1tdW5lIiA9IGMoIlMxMDBBOSIsICJDRDgxIiwgIkZDR1IxQSIsICJHQlA1IiwgIlJVTlgzIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNEMzAwRSIsICJNTkRBIiwgIklMMThCUCIsICJJTDRJMSIsICJXREZZNCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlRSREMiLCAiVFJCQzEiLCAiSUZORyIsICJDRDE2MCIsICJJRklUTTEiKSwgCiAgICAgICAgICAgICAgICAgICAgICAiQ2hvbGFuZ2lvY3l0ZXMiID0gYygiQ0NMMiIsICJJUkYxIiwgIktSVDE5IiwgIkNDTDIwIiwgIklDQU0xIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJNQVAzSzEyIiwgIkVQU1RJMSIsICJQNEhBMSIsICJQRUFLMSIsICJTRUMyNEEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkxDTjIiLCAiUkFNUDEiLCAiSVRHQjQiLCAiQklLIiwgIkNDTDI4IiksIAogICAgICAgICAgICAgICAgICAgICAgIk1lc2VuY2h5bWFsIiA9IGMoKSwgCiAgICAgICAgICAgICAgICAgICAgICAiRW5kb3RoZWxpYWwiID0gYygiU09YMTgiLCAiUExDRzIiLCAiVEZQSTIiLCAiS0xGMiIsICJTVEMxIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJDWFhDNSIsICJOUFIzIiwgIkNESzYiLCAiQURHUkc2IiwgIlBER0ZCIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJSRlBMMSIsICJJVEdCMyIsICJBREFNVFM0IiwgIktMRjEzIiwgIkdQUjE4MiIpKQoKcGx0X2xpc3RfY29uZCA9IGxpc3QoKQpkZl9saXN0X2NvbmQgPSBsaXN0KCkKZm9yKGN0IGluIHVuaXF1ZShmaWx0X2NvbXBzJG1ham9yX2N0JGhlYWx0aHlfdl9lbWJvbGlzZWQkY2VsbHR5cGUpKXsKICBnID0gaWYoY3Q9PSJIZXBhdG9jeXRlcyIpICJtYWpvcl9jdF9oZXAiIGVsc2UgIm1ham9yX2N0IiAjdXNlIGNvcnJlY3QgSGVwIERFCiAgCiAgIyBwcmVwYXJlIGRhdGEgZnJhbWUKICBwbHRfcmVnID0gZmlsdF9jb21wc1tbZ11dJGhlYWx0aHlfdl9yZWdlbmVyYXRpbmdbLGMoMSwzLDQsNSldCiAgcGx0X3JlZyA9IHVuaXF1ZShwbHRfcmVnW3BsdF9yZWckY2VsbHR5cGU9PWN0LF0pCiAgcGx0X2VtYiA9IGZpbHRfY29tcHNbW2ddXSRoZWFsdGh5X3ZfZW1ib2xpc2VkWyxjKDEsMyw0LDUpXQogIHBsdF9lbWIgPSB1bmlxdWUocGx0X2VtYltwbHRfZW1iJGNlbGx0eXBlPT1jdCxdKQogIHJvd25hbWVzKHBsdF9yZWcpID0gcGx0X3JlZyRnZW5lCiAgcm93bmFtZXMocGx0X2VtYikgPSBwbHRfZW1iJGdlbmUKICAKICAjIGFkZCBGQy9wdmFsIGZvciBnZW5lcyB0aGF0IGFyZSBub3QgaW4gY29tbW9uCiAgcGx0X2RmID0gbWVyZ2UocGx0X2VtYiwgcGx0X3JlZywgYnkgPSAwLCBhbGwgPSBUKQogIHJvd25hbWVzKHBsdF9kZikgPSBwbHRfZGZbLDFdCiAgcGx0X2RmID0gcGx0X2RmWywtYygxLDMsNiw3KV0KICBjb2xuYW1lcyhwbHRfZGYpID0gYygiZ2VuZSIsICJGQ19lbWIiLCAicHZhbF9lbWIiLCAiRkNfcmVnIiwgInB2YWxfcmVnIikKICBwbHRfZGYkZ2VuZSA9IHJvd25hbWVzKHBsdF9kZikKICBwbHRfZGYkRkNfZW1iW2lzLm5hKHBsdF9kZiRGQ19lbWIpXSA9IDAKICBwbHRfZGYkRkNfcmVnW2lzLm5hKHBsdF9kZiRGQ19yZWcpXSA9IDAKICBwbHRfZGYkcHZhbF9lbWJbaXMubmEocGx0X2RmJHB2YWxfZW1iKV0gPSAxCiAgcGx0X2RmJHB2YWxfcmVnW2lzLm5hKHBsdF9kZiRwdmFsX3JlZyldID0gMQogIAogICMgY29uZGl0aW9uIGxhYmVscwogIHBsdF9kZiRjb25kID0gaWZlbHNlKHBsdF9kZiRGQ19lbWI8PSgtMC4yKSAmIHBsdF9kZiRwdmFsX2VtYjw9MC4wNSAmIHBsdF9kZiRGQ19yZWc+PTAsICJlbWJvbGlzZWQiLAogICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShwbHRfZGYkRkNfcmVnPD0oLTAuMikgJiBwbHRfZGYkcHZhbF9yZWc8PTAuMDUgJiBwbHRfZGYkRkNfZW1iPj0wLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicmVnZW5lcmF0aW5nIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKHBsdF9kZiRGQ19yZWc8PSgtMC4yKSAmIHBsdF9kZiRwdmFsX3JlZzw9MC4wNSAmIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwbHRfZGYkRkNfZW1iPD0oLTAuMikgJiBwbHRfZGYkcHZhbF9lbWI8PTAuMDUsICJib3RoIiwib3RoZXIiKSkpCiAgcGx0X2RmJGNvbmQgPSBmYWN0b3IocGx0X2RmJGNvbmQsIGxldmVscyA9IGMoImJvdGgiLCAiZW1ib2xpc2VkIiwgInJlZ2VuZXJhdGluZyIsICJvdGhlciIpKQogIHBsdF9kZiA9IHBsdF9kZltvcmRlcihwbHRfZGYkY29uZCwgZGVjcmVhc2luZyA9IFQpLF0KICAKICAjIGdlbmVzIHRvIHBsb3QKICBiX2dfcGx0ID0gZ2VuZXNfdG9fcGxvdFtbY3RdXVsxOjVdCiAgZW1iX2dfcGx0ID0gZ2VuZXNfdG9fcGxvdFtbY3RdXVs2OjEwXQogIHJlZ19nX3BsdCA9IGdlbmVzX3RvX3Bsb3RbW2N0XV1bMTE6MTVdCiAgCiAgY29scyA9IGMoImJvdGgiID0gIiNDNTQ2MzUiLCAicmVnZW5lcmF0aW5nIiA9ICJzYWxtb24iLCAiZW1ib2xpc2VkIiA9ICJkYXJrcmVkIiwgIm90aGVyIiA9ICJncmV5ODUiKQogIHBsdCA9IGdncGxvdChwbHRfZGYsIGFlcyh4ID0gRkNfZW1iLCB5ID0gRkNfcmVnLCBjb2xvdXIgPSBjb25kKSkrCiAgICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwKSsKICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDApKwogICAgZ2VvbV9wb2ludCgpKwogICAgZ2VvbV9sYWJlbF9yZXBlbChkYXRhID0gcGx0X2RmW3BsdF9kZiRnZW5lICVpbiUgYyhlbWJfZ19wbHQsIHJlZ19nX3BsdCwgYl9nX3BsdCksXSwgCiAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMobGFiZWwgPSBnZW5lKSwgc2hvdy5sZWdlbmQgPSBGLCBtaW4uc2VnbWVudC5sZW5ndGggPSAwLCAKICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDIuNzUsIGxhYmVsLnBhZGRpbmcgPSAwLjE1KSsKICAgIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gY29scykrCiAgICBsYWJzKHRpdGxlID0gY3QsIHggPSAibG9nRkMoaGVhbHRoeSB2cyBlbWJvbGlzZWQpIiwgY29sb3VyID0gIkNvbmRpdGlvbiIsCiAgICAgICAgIHkgPSAibG9nRkMoaGVhbHRoeSB2cyByZWdlbmVyYXRpbmcpIikrCiAgICB0aGVtZV9idygpKwogICAgdGhlbWUoYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KGNvbG91ciA9ICJibGFjayIpLAogICAgICAgICAgYXNwZWN0LnJhdGlvID0gMSkKICAKICBwbHRfbGlzdF9jb25kW1tjdF1dID0gcGx0Cn0KCnBkZigiZmlndXJlX3BhbmVscy9maWcyL0RFX2NvbmRfbWFqb3JfY2VsbHR5cGVzLnBkZiIsIGhlaWdodCA9IDUsIHdpZHRoID0gNiwgdXNlRGluZ2JhdHMgPSBGKQpwcmludChwbHRfbGlzdF9jb25kKQpkZXYub2ZmKCkKcGRmKCJmaWd1cmVfcGFuZWxzL2ZpZzIvREVfY29uZF9tYWpvcl9jZWxsdHlwZXNfbm9MZWcucGRmIiwgaGVpZ2h0ID0gNSwgd2lkdGggPSA2LCB1c2VEaW5nYmF0cyA9IEYpCnBsdF9saXN0X2NvbmQgPSBsYXBwbHkocGx0X2xpc3RfY29uZCwgZnVuY3Rpb24oeCkgeCt0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpKQpwcmludChwbHRfbGlzdF9jb25kKQpkZXYub2ZmKCkKYGBgCgpBbGwgY2VsbCB0eXBlcwoKYGBge3J9CnBsdF9saXN0X2NvbmQgPSBsaXN0KCkKZGZfbGlzdF9jb25kID0gbGlzdCgpCmZvcihjdCBpbiB1bmlxdWUoZmlsdF9jb21wcyRjZWxsX3R5cGUkaGVhbHRoeV92X2VtYm9saXNlZCRjZWxsdHlwZSkpewogIGcgPSBpZihjdD09IkhlcGF0b2N5dGVzIikgImNlbGxfdHlwZV9oZXAiIGVsc2UgImNlbGxfdHlwZSIgI3VzZSBjb3JyZWN0IEhlcCBERQogIAogICMgcHJlcGFyZSBkYXRhIGZyYW1lCiAgcGx0X3JlZyA9IGZpbHRfY29tcHNbW2ddXSRoZWFsdGh5X3ZfcmVnZW5lcmF0aW5nWyxjKDEsMyw0LDUpXQogIHBsdF9yZWcgPSB1bmlxdWUocGx0X3JlZ1twbHRfcmVnJGNlbGx0eXBlPT1jdCxdKQogIHBsdF9lbWIgPSBmaWx0X2NvbXBzW1tnXV0kaGVhbHRoeV92X2VtYm9saXNlZFssYygxLDMsNCw1KV0KICBwbHRfZW1iID0gdW5pcXVlKHBsdF9lbWJbcGx0X2VtYiRjZWxsdHlwZT09Y3QsXSkKICByb3duYW1lcyhwbHRfcmVnKSA9IHBsdF9yZWckZ2VuZQogIHJvd25hbWVzKHBsdF9lbWIpID0gcGx0X2VtYiRnZW5lCiAgCiAgIyBhZGQgRkMvcHZhbCBmb3IgZ2VuZXMgdGhhdCBhcmUgbm90IGluIGNvbW1vbgogIHBsdF9kZiA9IG1lcmdlKHBsdF9lbWIsIHBsdF9yZWcsIGJ5ID0gMCwgYWxsID0gVCkKICByb3duYW1lcyhwbHRfZGYpID0gcGx0X2RmWywxXQogIHBsdF9kZiA9IHBsdF9kZlssLWMoMSwzLDYsNyldCiAgY29sbmFtZXMocGx0X2RmKSA9IGMoImdlbmUiLCAiRkNfZW1iIiwgInB2YWxfZW1iIiwgIkZDX3JlZyIsICJwdmFsX3JlZyIpCiAgcGx0X2RmJGdlbmUgPSByb3duYW1lcyhwbHRfZGYpCiAgcGx0X2RmJEZDX2VtYltpcy5uYShwbHRfZGYkRkNfZW1iKV0gPSAwCiAgcGx0X2RmJEZDX3JlZ1tpcy5uYShwbHRfZGYkRkNfcmVnKV0gPSAwCiAgcGx0X2RmJHB2YWxfZW1iW2lzLm5hKHBsdF9kZiRwdmFsX2VtYildID0gMQogIHBsdF9kZiRwdmFsX3JlZ1tpcy5uYShwbHRfZGYkcHZhbF9yZWcpXSA9IDEKICAKICAjIGNvbmRpdGlvbiBsYWJlbHMKICBwbHRfZGYkY29uZCA9IGlmZWxzZShwbHRfZGYkRkNfZW1iPD0oLTAuMikgJiBwbHRfZGYkcHZhbF9lbWI8PTAuMDUgJiBwbHRfZGYkRkNfcmVnPj0wLCAiZW1ib2xpc2VkIiwKICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UocGx0X2RmJEZDX3JlZzw9KC0wLjIpICYgcGx0X2RmJHB2YWxfcmVnPD0wLjA1ICYgcGx0X2RmJEZDX2VtYj49MCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInJlZ2VuZXJhdGluZyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShwbHRfZGYkRkNfcmVnPD0oLTAuMikgJiBwbHRfZGYkcHZhbF9yZWc8PTAuMDUgJiAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGx0X2RmJEZDX2VtYjw9KC0wLjIpICYgcGx0X2RmJHB2YWxfZW1iPD0wLjA1LCAiYm90aCIsIm90aGVyIikpKQogIHBsdF9kZiRjb25kID0gZmFjdG9yKHBsdF9kZiRjb25kLCBsZXZlbHMgPSBjKCJib3RoIiwgImVtYm9saXNlZCIsICJyZWdlbmVyYXRpbmciLCAib3RoZXIiKSkKICBwbHRfZGYgPSBwbHRfZGZbb3JkZXIocGx0X2RmJGNvbmQsIGRlY3JlYXNpbmcgPSBUKSxdCiAgCiAgIyBnZW5lcyB0byBwbG90CiAgb3JkID0gb3JkZXIocGx0X2RmJEZDX2VtYitwbHRfZGYkRkNfcmVnLCBkZWNyZWFzaW5nID0gRikKICBiX2dfcGx0ID0gcGx0X2RmJGdlbmVbb3JkXVtwbHRfZGYkY29uZFtvcmRdPT0iYm90aCIgJiBwbHRfZGYkcHZhbF9lbWJbb3JkXTw9MC4wNSAmIHBsdF9kZiRwdmFsX3JlZ1tvcmRdPD0wLjA1XVsxOjVdCiAgb3JkID0gb3JkZXIocGx0X2RmJEZDX2VtYiwgZGVjcmVhc2luZyA9IEYpCiAgZW1iX2dfcGx0ID0gcGx0X2RmJGdlbmVbb3JkXVtwbHRfZGYkY29uZFtvcmRdPT0iZW1ib2xpc2VkIiAmIHBsdF9kZiRwdmFsX2VtYltvcmRdPD0wLjA1XVsxOjVdCiAgb3JkID0gb3JkZXIocGx0X2RmJEZDX3JlZywgZGVjcmVhc2luZyA9IEYpCiAgcmVnX2dfcGx0ID0gcGx0X2RmJGdlbmVbb3JkXVtwbHRfZGYkY29uZFtvcmRdPT0icmVnZW5lcmF0aW5nIiAmIHBsdF9kZiRwdmFsX3JlZ1tvcmRdPD0wLjA1XVsxOjVdCiAgCiAgY29scyA9IGMoImJvdGgiID0gIiNDNTQ2MzUiLCAicmVnZW5lcmF0aW5nIiA9ICJzYWxtb24iLCAiZW1ib2xpc2VkIiA9ICJkYXJrcmVkIiwgIm90aGVyIiA9ICJncmV5ODUiKQogIHBsdCA9IGdncGxvdChwbHRfZGYsIGFlcyh4ID0gRkNfZW1iLCB5ID0gRkNfcmVnLCBjb2xvdXIgPSBjb25kKSkrCiAgICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwKSsKICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDApKwogICAgZ2VvbV9wb2ludCgpKwogICAgZ2VvbV9sYWJlbF9yZXBlbChkYXRhID0gcGx0X2RmW3BsdF9kZiRnZW5lICVpbiUgYyhlbWJfZ19wbHQsIHJlZ19nX3BsdCwgYl9nX3BsdCksXSwgCiAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMobGFiZWwgPSBnZW5lKSwgc2hvdy5sZWdlbmQgPSBGLCBtaW4uc2VnbWVudC5sZW5ndGggPSAwLCAKICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDIuNzUsIGxhYmVsLnBhZGRpbmcgPSAwLjE1KSsKICAgIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gY29scykrCiAgICBsYWJzKHRpdGxlID0gY3QsIHggPSAibG9nRkMoaGVhbHRoeSB2cyBlbWJvbGlzZWQpIiwgY29sb3VyID0gIkNvbmRpdGlvbiIsCiAgICAgICAgIHkgPSAibG9nRkMoaGVhbHRoeSB2cyByZWdlbmVyYXRpbmcpIikrCiAgICB0aGVtZV9idygpKwogICAgdGhlbWUoYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KGNvbG91ciA9ICJibGFjayIpLAogICAgICAgICAgYXNwZWN0LnJhdGlvID0gMSkKICAKICBwbHRfbGlzdF9jb25kW1tjdF1dID0gcGx0Cn0KCnBkZigiZmlndXJlX3BhbmVscy9maWcyL0RFX2NvbmRfYWxsX2NlbGx0eXBlcy5wZGYiLCBoZWlnaHQgPSA1LCB3aWR0aCA9IDYsIHVzZURpbmdiYXRzID0gRikKcHJpbnQocGx0X2xpc3RfY29uZCkKZGV2Lm9mZigpCnBkZigiZmlndXJlX3BhbmVscy9maWcyL0RFX2NvbmRfYWxsX2NlbGx0eXBlc19ub0xlZy5wZGYiLCBoZWlnaHQgPSA1LCB3aWR0aCA9IDYsIHVzZURpbmdiYXRzID0gRikKcGx0X2xpc3RfY29uZCA9IGxhcHBseShwbHRfbGlzdF9jb25kLCBmdW5jdGlvbih4KSB4K3RoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikpCnByaW50KHBsdF9saXN0X2NvbmQpCmRldi5vZmYoKQpgYGAKCkNvdW50IERFIGdlbmVzIHBlciBjZWxsIHR5cGUgaW4gY29uZGl0aW9ucyAtIG1ham9yIGNlbGwgdHlwZXMKCmBgYHtyfQpkZV9kZiA9IGZpbHRfY29tcHMkbWFqb3JfY3QkaGVhbHRoeV92X2VtYm9saXNlZApkZV9kZiA9IGRlX2RmW2RlX2RmJHBfdmFsX2Fkajw9MC4wNSAmIGFicyhkZV9kZiRhdmdfbG9nRkMpPj0wLjIsXQpnZW5lc191cCA9IHRhcHBseShkZV9kZiRnZW5lW2RlX2RmJGF2Z19sb2dGQz4wXSwgZGVfZGYkY2VsbHR5cGVbZGVfZGYkYXZnX2xvZ0ZDPjBdLCBsaXN0KQpnZW5lc19kbiA9IHRhcHBseShkZV9kZiRnZW5lW2RlX2RmJGF2Z19sb2dGQzwwXSwgZGVfZGYkY2VsbHR5cGVbZGVfZGYkYXZnX2xvZ0ZDPDBdLCBsaXN0KQpkZV9oZXAgPSBmaWx0X2NvbXBzJG1ham9yX2N0X2hlcCRoZWFsdGh5X3ZfZW1ib2xpc2VkCmdlbmVzX3VwJEhlcGF0b2N5dGVzID0gZGVfaGVwJGdlbmVbZGVfaGVwJGF2Z19sb2dGQz49MC4yICYgZGVfaGVwJHBfdmFsX2Fkajw9MC4wNV0KZ2VuZXNfZG4kSGVwYXRvY3l0ZXMgPSBkZV9oZXAkZ2VuZVtkZV9oZXAkYXZnX2xvZ0ZDPD0oLTAuMikgJiBkZV9oZXAkcF92YWxfYWRqPD0wLjA1XQpkZV9kZl9nID0gcmJpbmQocmVzaGFwZTI6Om1lbHQoZ2VuZXNfdXApLCByZXNoYXBlMjo6bWVsdChnZW5lc19kbikpCmRlX2RmX2ckZGVkaXIgPSBjKHJlcCgiaGlnaGVyIGluIGhlYWx0aHkiLCBsZW5ndGgodW5saXN0KGdlbmVzX3VwKSkpLCAKICAgICAgICAgICAgICAgICAgcmVwKCJoaWdoZXIgaW4gZW1ib2xpc2VkIiwgbGVuZ3RoKHVubGlzdChnZW5lc19kbikpKSkKCmRlX2RmX3IgPSBmaWx0X2NvbXBzJG1ham9yX2N0JGhlYWx0aHlfdl9yZWdlbmVyYXRpbmcKZGVfZGZfciA9IGRlX2RmX3JbZGVfZGZfciRwX3ZhbF9hZGo8PTAuMDUgJiBhYnMoZGVfZGZfciRhdmdfbG9nRkMpPj0wLjIsXQpnZW5lc191cCA9IHRhcHBseShkZV9kZl9yJGdlbmVbZGVfZGZfciRhdmdfbG9nRkM+MF0sIGRlX2RmX3IkY2VsbHR5cGVbZGVfZGZfciRhdmdfbG9nRkM+MF0sIGxpc3QpCmdlbmVzX2RuID0gdGFwcGx5KGRlX2RmX3IkZ2VuZVtkZV9kZl9yJGF2Z19sb2dGQzwwXSwgZGVfZGZfciRjZWxsdHlwZVtkZV9kZl9yJGF2Z19sb2dGQzwwXSwgbGlzdCkKZGVfaGVwID0gZmlsdF9jb21wcyRtYWpvcl9jdF9oZXAkaGVhbHRoeV92X3JlZ2VuZXJhdGluZwpnZW5lc191cCRIZXBhdG9jeXRlcyA9IGRlX2hlcCRnZW5lW2RlX2hlcCRhdmdfbG9nRkM+PTAuMiAmIGRlX2hlcCRwX3ZhbF9hZGo8PTAuMDVdCmdlbmVzX2RuJEhlcGF0b2N5dGVzID0gZGVfaGVwJGdlbmVbZGVfaGVwJGF2Z19sb2dGQzw9KC0wLjIpICYgZGVfaGVwJHBfdmFsX2Fkajw9MC4wNV0KZGVfZGZfcl9nID0gcmJpbmQocmVzaGFwZTI6Om1lbHQoZ2VuZXNfdXApLCByZXNoYXBlMjo6bWVsdChnZW5lc19kbikpCmRlX2RmX3JfZyRkZWRpciA9IGMocmVwKCJoaWdoZXIgaW4gaGVhbHRoeSIsIGxlbmd0aCh1bmxpc3QoZ2VuZXNfdXApKSksIAogICAgICAgICAgICAgICAgICAgIHJlcCgiaGlnaGVyIGluIHJlZ2VuZXJhdGluZyIsIGxlbmd0aCh1bmxpc3QoZ2VuZXNfZG4pKSkpCgoKY291bnRzX2RlID0gcmJpbmQoZGF0YS5mcmFtZSh0YWJsZShkZV9kZl9nJEwxLCBkZV9kZl9nJGRlZGlyKSksIGRhdGEuZnJhbWUodGFibGUoZGVfZGZfcl9nJEwxLCBkZV9kZl9yX2ckZGVkaXIpKSkKY291bnRzX2RlJGNvbXAgPSByZXAoYygiaGVhbHRoeSB2cyBlbWJvbGlzZWQiLCAiaGVhbHRoeSB2cyByZWdlbmVyYXRpbmciKSwgZWFjaCA9IDEwKQpjb3VudHNfZGUkVmFyMiA9IGZhY3Rvcihjb3VudHNfZGUkVmFyMiwgCiAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoImhpZ2hlciBpbiBoZWFsdGh5IiwgImhpZ2hlciBpbiBlbWJvbGlzZWQiLCAiaGlnaGVyIGluIHJlZ2VuZXJhdGluZyIpKQoKcGx0ID0gZ2dwbG90KGNvdW50c19kZSwgYWVzKHggPSBWYXIxLCB5ID0gRnJlcSwgZmlsbCA9IFZhcjIpKSsKICBmYWNldF93cmFwKH5jb21wLCBucm93ID0gMikrCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiaGlnaGVyIGluIGhlYWx0aHkiID0gIm9yYW5nZSIsICJoaWdoZXIgaW4gcmVnZW5lcmF0aW5nIiA9ICJzYWxtb24iLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJoaWdoZXIgaW4gZW1ib2xpc2VkIiA9ICJkYXJrcmVkIikpKwogIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBjKDAsMCksIGxpbWl0cyA9IGMoMCwgNDAwMCkpKwogIGxhYnMoZmlsbCA9ICJERSBnZW5lcyIsIHggPSAiQ2VsbCB0eXBlcyIsIHkgPSAiIyBERSBnZW5lcyIpKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSsKICB0aGVtZV9jbGFzc2ljKCkrCiAgdGhlbWUobGVnZW5kLmp1c3RpZmljYXRpb249YygwLDEpLCBsZWdlbmQucG9zaXRpb249YygwLDEpLAogICAgICAgIGxlZ2VuZC5ib3guYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAidHJhbnNwYXJlbnQiLCBmaWxsID0gInRyYW5zcGFyZW50IiksCiAgICAgICAgbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gInRyYW5zcGFyZW50IiwgZmlsbCA9ICJ0cmFuc3BhcmVudCIpLAogICAgICAgIGxlZ2VuZC5rZXkuc2l6ZSA9IHVuaXQoMC40LCAiY20iKSwKICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoY29sb3VyID0gImJsYWNrIiksCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxLCB2anVzdCA9IDEpKQoKcGRmKCJmaWd1cmVfcGFuZWxzL2ZpZzIvYmFycGxvdF9kZWNvbmRfbWFqb3IucGRmIiwgaGVpZ2h0ID0gNSwgd2lkdGggPSAzLCB1c2VEaW5nYmF0cyA9IEYpCnByaW50KHBsdCkKZGV2Lm9mZigpCnBuZygiZmlndXJlX3BhbmVscy9maWcyL2JhcnBsb3RfZGVjb25kX21ham9yLnBuZyIsIGhlaWdodCA9IDUwMCwgd2lkdGggPSAzNTAsIGFudGlhbGlhcyA9ICJzdWJwaXhlbCIpCnByaW50KHBsdCkKZGV2Lm9mZigpCmBgYAoKQ291bnQgREUgZ2VuZXMgcGVyIGNlbGwgdHlwZSBpbiBjb25kaXRpb25zIC0gYWxsIGNlbGwgdHlwZXMKCmBgYHtyfQpkZV9kZiA9IGZpbHRfY29tcHMkY2VsbF90eXBlX3NpbXAkaGVhbHRoeV92X2VtYm9saXNlZApkZV9kZiA9IGRlX2RmW2RlX2RmJHBfdmFsX2Fkajw9MC4wNSAmIGFicyhkZV9kZiRhdmdfbG9nRkMpPj0wLjIsXQpnZW5lc191cCA9IHRhcHBseShkZV9kZiRnZW5lW2RlX2RmJGF2Z19sb2dGQz4wXSwgZGVfZGYkY2VsbHR5cGVbZGVfZGYkYXZnX2xvZ0ZDPjBdLCBsaXN0KQpnZW5lc19kbiA9IHRhcHBseShkZV9kZiRnZW5lW2RlX2RmJGF2Z19sb2dGQzwwXSwgZGVfZGYkY2VsbHR5cGVbZGVfZGYkYXZnX2xvZ0ZDPDBdLCBsaXN0KQpkZV9oZXAgPSBmaWx0X2NvbXBzJG1ham9yX2N0X2hlcCRoZWFsdGh5X3ZfZW1ib2xpc2VkCmdlbmVzX3VwJEhlcGF0b2N5dGVzID0gZGVfaGVwJGdlbmVbZGVfaGVwJGF2Z19sb2dGQz49MC4yICYgZGVfaGVwJHBfdmFsX2Fkajw9MC4wNV0KZ2VuZXNfZG4kSGVwYXRvY3l0ZXMgPSBkZV9oZXAkZ2VuZVtkZV9oZXAkYXZnX2xvZ0ZDPD0oLTAuMikgJiBkZV9oZXAkcF92YWxfYWRqPD0wLjA1XQpkZV9kZl9nID0gcmJpbmQocmVzaGFwZTI6Om1lbHQoZ2VuZXNfdXApLCByZXNoYXBlMjo6bWVsdChnZW5lc19kbikpCmRlX2RmX2ckZGVkaXIgPSBjKHJlcCgiaGlnaGVyIGluIGhlYWx0aHkiLCBsZW5ndGgodW5saXN0KGdlbmVzX3VwKSkpLCAKICAgICAgICAgICAgICAgICAgcmVwKCJoaWdoZXIgaW4gZW1ib2xpc2VkIiwgbGVuZ3RoKHVubGlzdChnZW5lc19kbikpKSkKCmRlX2RmX3IgPSBmaWx0X2NvbXBzJGNlbGxfdHlwZV9zaW1wJGhlYWx0aHlfdl9yZWdlbmVyYXRpbmcKZGVfZGZfciA9IGRlX2RmX3JbZGVfZGZfciRwX3ZhbF9hZGo8PTAuMDUgJiBhYnMoZGVfZGZfciRhdmdfbG9nRkMpPj0wLjIsXQpnZW5lc191cCA9IHRhcHBseShkZV9kZl9yJGdlbmVbZGVfZGZfciRhdmdfbG9nRkM+MF0sIGRlX2RmX3IkY2VsbHR5cGVbZGVfZGZfciRhdmdfbG9nRkM+MF0sIGxpc3QpCmdlbmVzX2RuID0gdGFwcGx5KGRlX2RmX3IkZ2VuZVtkZV9kZl9yJGF2Z19sb2dGQzwwXSwgZGVfZGZfciRjZWxsdHlwZVtkZV9kZl9yJGF2Z19sb2dGQzwwXSwgbGlzdCkKZGVfaGVwID0gZmlsdF9jb21wcyRtYWpvcl9jdF9oZXAkaGVhbHRoeV92X3JlZ2VuZXJhdGluZwpnZW5lc191cCRIZXBhdG9jeXRlcyA9IGRlX2hlcCRnZW5lW2RlX2hlcCRhdmdfbG9nRkM+PTAuMiAmIGRlX2hlcCRwX3ZhbF9hZGo8PTAuMDVdCmdlbmVzX2RuJEhlcGF0b2N5dGVzID0gZGVfaGVwJGdlbmVbZGVfaGVwJGF2Z19sb2dGQzw9KC0wLjIpICYgZGVfaGVwJHBfdmFsX2Fkajw9MC4wNV0KZGVfZGZfcl9nID0gcmJpbmQocmVzaGFwZTI6Om1lbHQoZ2VuZXNfdXApLCByZXNoYXBlMjo6bWVsdChnZW5lc19kbikpCmRlX2RmX3JfZyRkZWRpciA9IGMocmVwKCJoaWdoZXIgaW4gaGVhbHRoeSIsIGxlbmd0aCh1bmxpc3QoZ2VuZXNfdXApKSksIAogICAgICAgICAgICAgICAgICAgIHJlcCgiaGlnaGVyIGluIHJlZ2VuZXJhdGluZyIsIGxlbmd0aCh1bmxpc3QoZ2VuZXNfZG4pKSkpCgpjb3VudHNfZGUgPSByYmluZChkYXRhLmZyYW1lKHRhYmxlKGRlX2RmX2ckTDEsIGRlX2RmX2ckZGVkaXIpKSwgCiAgICAgICAgICAgICAgICAgIGRhdGEuZnJhbWUodGFibGUoZGVfZGZfcl9nJEwxLCBkZV9kZl9yX2ckZGVkaXIpKSkKY291bnRzX2RlJGNvbXAgPSByZXAoYygiaGVhbHRoeSB2cyBlbWJvbGlzZWQiLCAiaGVhbHRoeSB2cyByZWdlbmVyYXRpbmciKSwgZWFjaCA9IDE0KQpjb3VudHNfZGUkVmFyMiA9IGZhY3Rvcihjb3VudHNfZGUkVmFyMiwgCiAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoImhpZ2hlciBpbiBoZWFsdGh5IiwgImhpZ2hlciBpbiBlbWJvbGlzZWQiLCAiaGlnaGVyIGluIHJlZ2VuZXJhdGluZyIpKQoKcGx0ID0gZ2dwbG90KGNvdW50c19kZSwgYWVzKHggPSBWYXIxLCB5ID0gRnJlcSwgZmlsbCA9IFZhcjIpKSsKICBmYWNldF93cmFwKH5jb21wKSsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJoaWdoZXIgaW4gaGVhbHRoeSIgPSAib3JhbmdlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiaGlnaGVyIGluIHJlZ2VuZXJhdGluZyIgPSAic2FsbW9uIiwgImhpZ2hlciBpbiBlbWJvbGlzZWQiID0gImRhcmtyZWQiKSkrCiAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwwKSwgbGltaXRzID0gYygwLCAzNTAwKSkrCiAgbGFicyhmaWxsID0gIkRFIGdlbmVzIiwgeCA9ICJDZWxsIHR5cGVzIiwgeSA9ICIjIERFIGdlbmVzIikrCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpKwogIHRoZW1lX2NsYXNzaWMoKSsKICB0aGVtZShsZWdlbmQuanVzdGlmaWNhdGlvbj1jKDAsMSksIGxlZ2VuZC5wb3NpdGlvbj1jKDAsMSksCiAgICAgICAgbGVnZW5kLmJveC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJ0cmFuc3BhcmVudCIsIGZpbGwgPSAidHJhbnNwYXJlbnQiKSwKICAgICAgICBsZWdlbmQuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAidHJhbnNwYXJlbnQiLCBmaWxsID0gInRyYW5zcGFyZW50IiksCiAgICAgICAgbGVnZW5kLmtleS5zaXplID0gdW5pdCgwLjQsICJjbSIpLAogICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChjb2xvdXIgPSAiYmxhY2siKSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEsIHZqdXN0ID0gMSkpCgpwZGYoImZpZ3VyZV9wYW5lbHMvZmlnMi9iYXJwbG90X2RlY29uZF9hbGwucGRmIiwgaGVpZ2h0ID0gNCwgd2lkdGggPSA2LCB1c2VEaW5nYmF0cyA9IEYpCnByaW50KHBsdCkKZGV2Lm9mZigpCnBuZygiZmlndXJlX3BhbmVscy9maWcyL2JhcnBsb3RfZGVjb25kX2FsbC5wbmciLCBoZWlnaHQgPSAzNTAsIHdpZHRoID0gNTAwLCBhbnRpYWxpYXMgPSAic3VicGl4ZWwiKQpwcmludChwbHQpCmRldi5vZmYoKQpgYGAKCgojIyBTdXBwbGVtZW50YXJ5CkdlbmUgYW5kIFVNSSBjb3VudHMgcGVyIG1ham9yIGNlbGwgdHlwZSBhbmQgY29uZGl0aW9uCgpgYGB7cn0KcGxvdF9kZiA9IGFsbGNlbGxzX2Nzc0BtZXRhLmRhdGEKcGxvdF9kZiRDb25kaXRpb24gPSBmYWN0b3IocGxvdF9kZiRDb25kaXRpb24sIGxldmVscyA9IGMoImhlYWx0aHkiLCAiZW1ib2xpc2VkIiwgInJlZ2VuZXJhdGluZyIpKQpwbG90X2RmJG1ham9yX2N0ID0gZmFjdG9yKHBsb3RfZGYkbWFqb3JfY3QsIGxldmVscyA9IGMoIkhlcGF0b2N5dGVzIiwgIkVuZG90aGVsaWFsIiwgIkNob2xhbmdpb2N5dGVzIiwgIkltbXVuZSIsICJNZXNlbmNoeW1hbCIpKQoKdmlvX2NvdW50c19jdCA9IGdncGxvdChwbG90X2RmWyFpcy5uYShwbG90X2RmJG1ham9yX2N0KSxdLCAKICAgICAgICAgICAgICAgICAgICAgICBhZXMoeSA9IG5Db3VudF9TQ1QsIHggPSBDb25kaXRpb24sIGZpbGwgPSBDb25kaXRpb24pKSsKICBmYWNldF93cmFwKH5tYWpvcl9jdCwgc2NhbGVzID0gImZyZWVfeCIpKwogIGdlb21fdmlvbGluKCkrCiAgc2NhbGVfeV9sb2cxMChuYW1lID0gIiMgVU1JIChub3JtYWxpc2VkKSIpKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNvbGNvbmQpKwogIHRoZW1lKHBhbmVsLmdyaWQubWFqb3IueSA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAiZ3JleTg1IiksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dCgpLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSA5KSwKICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSwKICAgICAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA5KSwKICAgICAgICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiLCBjb2xvdXIgPSAiYmxhY2siLCBzaXplID0gMC45KSkKCnBkZigiZmlndXJlX3BhbmVscy9maWcyL3Zpb2xpbl9uY291bnRzX21ham9yX2NlbGx0eXBlLnBkZiIsIGhlaWdodCA9IDQsIHdpZHRoID0gNywgdXNlRGluZ2JhdHMgPSBGKQpwcmludCh2aW9fY291bnRzX2N0KQpkZXYub2ZmKCkKcG5nKCJmaWd1cmVfcGFuZWxzL2ZpZzIvdmlvbGluX25jb3VudHNfbWFqb3JfY2VsbHR5cGUucG5nIiwgaGVpZ2h0ID0gNDI1LCB3aWR0aCA9IDU1MCwgYW50aWFsaWFzID0gInN1YnBpeGVsIikKcHJpbnQodmlvX2NvdW50c19jdCkKZGV2Lm9mZigpCgp2aW9fY291bnRzX2N0ID0gZ2dwbG90KHBsb3RfZGZbIWlzLm5hKHBsb3RfZGYkbWFqb3JfY3QpLF0sIAogICAgICAgICAgICAgICAgICAgICAgIGFlcyh5ID0gbkZlYXR1cmVfU0NULCB4ID0gQ29uZGl0aW9uLCBmaWxsID0gQ29uZGl0aW9uKSkrCiAgZmFjZXRfd3JhcCh+bWFqb3JfY3QsIHNjYWxlcyA9ICJmcmVlX3giKSsKICBnZW9tX3Zpb2xpbigpKwogIHNjYWxlX3lfbG9nMTAobmFtZSA9ICIjIEdlbmVzIikrCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY29sY29uZCkrCiAgdGhlbWUocGFuZWwuZ3JpZC5tYWpvci55ID0gZWxlbWVudF9saW5lKGNvbG91ciA9ICJncmV5ODUiKSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsCiAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KCksCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDkpLAogICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLAogICAgICAgIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDkpLAogICAgICAgIHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIsIGNvbG91ciA9ICJibGFjayIsIHNpemUgPSAwLjkpKQoKcGRmKCJmaWd1cmVfcGFuZWxzL2ZpZzIvdmlvbGluX25nZW5lc19tYWpvcl9jZWxsdHlwZS5wZGYiLCBoZWlnaHQgPSA0LCB3aWR0aCA9IDcsIHVzZURpbmdiYXRzID0gRikKcHJpbnQodmlvX2NvdW50c19jdCkKZGV2Lm9mZigpCnBuZygiZmlndXJlX3BhbmVscy9maWcyL3Zpb2xpbl9uZ2VuZXNfbWFqb3JfY2VsbHR5cGUucG5nIiwgaGVpZ2h0ID0gNDI1LCB3aWR0aCA9IDU1MCwgYW50aWFsaWFzID0gInN1YnBpeGVsIikKcHJpbnQodmlvX2NvdW50c19jdCkKZGV2Lm9mZigpCmBgYAoKblVNSSBpbiBmaWx0ZXJlZCBhbmQga2VwdCBjZWxscwoKYGBge3J9CmNfbWV0YSA9IFJlZHVjZShyYmluZCwgbGFwcGx5KGNvbmRfc3JhdCwgZnVuY3Rpb24oeCkgeEBtZXRhLmRhdGEpKVssYygxMSwxMiwxMywxNCwxNSwxNywyMyldCmhfbWV0YSA9IFJlZHVjZShyYmluZCwgbGFwcGx5KGhlYWx0aHlfc3JhdCwgZnVuY3Rpb24oeCkgeEBtZXRhLmRhdGEpKVssYygxMSwxMiwxMywxNCwxNSwxNywyMyldCmFsbF9tZXRhID0gcmJpbmQoaF9tZXRhLCBjX21ldGEpCgphbGxfbWV0YSRrZWVwX2FsbGZpbHQgPSBmYWN0b3IoYygiTm8iLCAiWWVzIilbYWxsX21ldGEka2VlcF9hbGxmaWx0KzFdLCBsZXZlbHMgPSBjKCJZZXMiLCAiTm8iKSkKYWxsX21ldGEkTmFtZSA9IGZhY3RvcihhbGxfbWV0YSROYW1lLCAKICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBwYXN0ZTAoInNjXyIsIGMocGFzdGUwKCJIIiwxOjMpLHBhc3RlMCgiRSIsYygxOjMsNTo3KSkscGFzdGUwKCJSIixjKDE6Myw1OjcpKSkpKQpsZXZlbHMoYWxsX21ldGEkTmFtZSkgPSBwYXN0ZTAoInNjXyIsIGMocGFzdGUwKCJIIiwxOjMpLHBhc3RlMCgiRSIsMTo2KSxwYXN0ZTAoIlIiLDE6NikpKQoKbl9jZWxscyA9IGFsbF9tZXRhICU+JSBjb3VudChOYW1lLCBGcmFjdGlvbiwga2VlcF9hbGxmaWx0KQoKcGx0ID0gZ2dwbG90KGFsbF9tZXRhLCBhZXMoeCA9IEZyYWN0aW9uLCB5ID0gbkNvdW50X1NDVCwgZmlsbCA9IGtlZXBfYWxsZmlsdCwgY29sb3VyID0ga2VlcF9hbGxmaWx0KSkrCiAgZmFjZXRfd3JhcCh+TmFtZSwgc2NhbGVzID0gImZyZWUiLCBucm93ID0gMykrCiAgZ2VvbV92aW9saW4oc2NhbGUgPSAid2lkdGgiKSsKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoIlllcyIgPSAiZ3JleTIwIiwiTm8iID0gImdyZXk4MCIpKSsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJZZXMiID0gImdyZXkyMCIsIk5vIiA9ICJncmV5ODAiKSkrCiAgc2NhbGVfeV9sb2cxMCgpKwogIGxhYnMoeSA9ICJuVU1JIiwgY29sb3VyID0gImtlZXAiLCBmaWxsID0gImtlZXAiKSsKICB0aGVtZShzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiLCBjb2xvdXIgPSAiYmxhY2siLCBzaXplID0gMSksCiAgICAgICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChtYXJnaW4gPSBtYXJnaW4oMiwwLDIsMCksIHNpemUgPSA5KSwKICAgICAgICBheGlzLnRpY2tzID0gZWxlbWVudF9saW5lKCksIAogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSA2LjUpKQoKcGRmKCJmaWd1cmVfcGFuZWxzL2ZpZzIvZmlsdGVyaW5nX25VTUkucGRmIiwgaGVpZ2h0ID0gMy4zLCB3aWR0aCA9IDcuMSwgdXNlRGluZ2JhdHMgPSBGKQpwcmludChwbHQpCmRldi5vZmYoKQpgYGAKClVNQVAgd2l0aCBoZWFsdGh5IGRvbm9ycyBzcGxpdAoKYGBge3IsIGZpZy5oZWlnaHQ9MiwgZmlnLndpZHRoPTN9CnBsb3RfZGYgPSBkYXRhLmZyYW1lKGFsbGNlbGxzX2Nzc0ByZWR1Y3Rpb25zJHVtYXBfY3NzQGNlbGwuZW1iZWRkaW5ncykKcGxvdF9kZiREb25vciA9IGZhY3RvcihhbGxjZWxsc19jc3NAbWV0YS5kYXRhJE5hbWUpCnBsb3RfZGYkRG9ub3IgPSBwbHlyOjpyZXZhbHVlKHBsb3RfZGYkRG9ub3IsIGMoInNjX0U1IiA9ICJzY19FNCIsICJzY19SNSIgPSAic2NfUjQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAic2NfRTYiID0gInNjX0U1IiwgInNjX1I2IiA9ICJzY19SNSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInNjX0U3IiA9ICJzY19FNiIsICJzY19SNyIgPSAic2NfUjYiKSkKcGxvdF9kZiREb25vciA9IGZhY3RvcihwbG90X2RmJERvbm9yLCBsZXZlbHMgPSBjKCJzY19IMSIsICJzY19IMiIsICJzY19IMyIsICJzY19FMSIsICJzY19SMSIsICJzY19FMiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInNjX1IyIiwgInNjX0UzIiwgInNjX1IzIiwgInNjX0U0IiwgInNjX1I0IiwgInNjX0U1IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAic2NfUjUiLCAic2NfRTYiLCAic2NfUjYiKSkKcGxvdF9kZiRDb25kaXRpb24gPSBmYWN0b3IoYWxsY2VsbHNfY3NzQG1ldGEuZGF0YSRDb25kaXRpb24sIAogICAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJoZWFsdGh5IiwgImVtYm9saXNlZCIsICJyZWdlbmVyYXRpbmciKSkKcGxvdF9kZiRtYWpvcl9jdCA9IGFsbGNlbGxzX2Nzc0BtZXRhLmRhdGEkbWFqb3JfY3QKcGxvdF9kZiRhbGxjZWxsc19tYWpvciA9IGFsbGNlbGxzX2Nzc0BtZXRhLmRhdGEkYWxsY2VsbHNfbWFqb3IKcGxvdF9kZiRtYWpvcl9jdFtpcy5uYShwbG90X2RmJG1ham9yX2N0KV0gPSBwbG90X2RmJGFsbGNlbGxzX21ham9yW2lzLm5hKHBsb3RfZGYkbWFqb3JfY3QpXQpwbG90X2RmJG1ham9yX2N0W3Bsb3RfZGYkbWFqb3JfY3Q9PSJEaXZpZGluZyBjZWxscyJdID0gIkltbXVuZSIgIyB0aGUgZGV0ZWN0ZWQgZGl2aWRpbmcgY2VsbHMgYXJlIG1vc3RseSAoaWYgbm90IGFsbCkgaW1tdW5lIApwbG90X2RmJG1ham9yX2N0ID0gZmFjdG9yKHBsb3RfZGYkbWFqb3JfY3QsIGxldmVscyA9IGMoIkhlcGF0b2N5dGVzIiwgIkVuZG90aGVsaWFsIiwiSW1tdW5lIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJDaG9sYW5naW9jeXRlcyIsIk1lc2VuY2h5bWFsIiwgIkRvdWJsZXRzIikpCgpwbHQgPSBnZ3Bsb3QocGxvdF9kZltzYW1wbGUoMTpucm93KHBsb3RfZGYpLCBucm93KHBsb3RfZGYpLCByZXBsYWNlID0gRiksXSwgCiAgICAgICAgICAgICBhZXMoeCA9IFVNQVBDU1NfMSwgeSA9IFVNQVBDU1NfMiwgY29sb3VyID0gbWFqb3JfY3QpKSsKICBmYWNldF93cmFwKH5Eb25vciwgZHJvcCA9IFQsIG5yb3cgPSAzLCBuY29sID0gNSkrCiAgZ2VvbV9wb2ludChzaXplID0gMC4wOCkrCiAgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KHNpemUgPSAzKSwgdGl0bGUgPSAiRG9ub3JzIikpKwogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gY29sc21ham9yKSsKICB0aGVtZV9jbGFzc2ljKCkrCiAgdGhfZ2VuKwogIHRoZW1lKGF4aXMubGluZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpY2tzID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gOCwgbWFyZ2luID0gbWFyZ2luKDAuMDYsMCwwLjA2LDAsICJjbSIpKSwKICAgICAgICBzdHJpcC5iYWNrZ3JvdW5kLnggPSBlbGVtZW50X3JlY3Qoc2l6ZSA9IDAuNSwgY29sb3VyID0gInRyYW5zcGFyZW50IiksCiAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMCksCiAgICAgICAgYXNwZWN0LnJhdGlvID0gMSkKCnBkZigiZmlndXJlX3BhbmVscy9maWcyL3VtYXBBbGxfZnJlc2hfZG9ub3JzX3NwbGl0LnBkZiIsIAogICAgdXNlRGluZ2JhdHMgPSBGLCBoZWlnaHQgPSA0LjEsIHdpZHRoID0gNi40KQpwcmludChwbHQpCmRldi5vZmYoKQpwbmcoImZpZ3VyZV9wYW5lbHMvZmlnMi91bWFwQWxsX2ZyZXNoX2Rvbm9yc19zcGxpdC5wbmciLCAKICAgIGhlaWdodD04LCB3aWR0aD0xNSwgdW5pdD0iY20iLCByZXM9NjAwLCBhbnRpYWxpYXMgPSAic3VicGl4ZWwiKQpwcmludChwbHQpCmRldi5vZmYoKQpwZGYoImZpZ3VyZV9wYW5lbHMvZmlnMi91bWFwQWxsX2ZyZXNoX2Rvbm9yc19ub0xlZ19zcGxpdC5wZGYiLCAKICAgIHVzZURpbmdiYXRzID0gRiwgaGVpZ2h0ID0gNC4xLCB3aWR0aCA9IDUuOCkKcHJpbnQocGx0K3RoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikpCmRldi5vZmYoKQpwbmcoImZpZ3VyZV9wYW5lbHMvZmlnMi91bWFwQWxsX2ZyZXNoX2Rvbm9yc19ub0xlZ19zcGxpdC5wbmciLCAKICAgIGhlaWdodD04LCB3aWR0aD0xMSwgdW5pdD0iY20iLCByZXM9NjAwLCBhbnRpYWxpYXMgPSAic3VicGl4ZWwiKQpwcmludChwbHQrdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSkKZGV2Lm9mZigpCnBkZigiZmlndXJlX3BhbmVscy9maWcyL3VtYXBBbGxfZnJlc2hfZG9ub3JzX3NwbGl0X2NvbmQucGRmIiwgCiAgICB1c2VEaW5nYmF0cyA9IEYsIGhlaWdodCA9IDQuMSwgd2lkdGggPSA2LjQpCnByaW50KHBsdCtmYWNldF93cmFwKENvbmRpdGlvbn5Eb25vciwgZHJvcCA9IFQsIG5yb3cgPSAzLCBuY29sID0gNSkpCmRldi5vZmYoKQpwbmcoImZpZ3VyZV9wYW5lbHMvZmlnMi91bWFwQWxsX2ZyZXNoX2Rvbm9yc19zcGxpdF9jb25kLnBuZyIsIAogICAgaGVpZ2h0PTgsIHdpZHRoPTE1LCB1bml0PSJjbSIsIHJlcz02MDAsIGFudGlhbGlhcyA9ICJzdWJwaXhlbCIpCnByaW50KHBsdCtmYWNldF93cmFwKENvbmRpdGlvbn5Eb25vciwgZHJvcCA9IFQsIG5yb3cgPSAzLCBuY29sID0gNSkpCmRldi5vZmYoKQpgYGAKCgoKIyBGaWd1cmUgMwojIyBNYWluIEZpZ3VyZQpab25hdGlvbiBiZXR3ZWVuIGNvbmRpdGlvbnMKCmBgYHtyfQojIGdlbmUgZXhwcmVzc2lvbgpoZXBfY2VsbHMgPSByZWFkUkRTKGZpbGUgPSAicmVzdWx0cy96b25hdGlvbl9jb25kL2hlcF9jZWxsc196b25hdGlvbl9yYW5rLlJEUyIpCgojIGZpdHRlZCBleHByZXNzaW9uCmhlcF9zaWdfZml0cyA9IHJlYWRSRFMoZmlsZSA9ICJyZXN1bHRzL3pvbmF0aW9uX2NvbmQvaGVwX3NpZ19maXRzLlJEUyIpCmhlcF9maXRzX3F2YWwgPSByZWFkUkRTKGZpbGUgPSAicmVzdWx0cy96b25hdGlvbl9jb25kL2hlcF9maXRzX3F2YWwuUkRTIikKCiMgR08gYW5kIGNsdXN0ZXJzCmhlcF9yZXNfbGlzdCA9IHJlYWRSRFMoZmlsZSA9ICJyZXN1bHRzL3pvbmF0aW9uX2NvbmQvaGVwX2dvdF9jbHVzdGVyaW5nX2xpc3QuUkRTIikKCmdfbGlzdCA9IGMoICMgZW1ib2xpc2VkIGNsdXN0ZXJzCiAgIkNPWDdDIiwgIyBveHlnZW4gdHJhbnNwb3J0IGNoYWluIChhbHNvIGluIHJlZ2VuIDIpCiAgIkNZUDM5QTEiLCAjIHN0ZXJvaWQgbWV0YWJvbGlzbQogICJBUkcxIiwgIyBvcmdhbmljIGFjaWQgY2F0YWJvbGljIHByb2Nlc3MgKGFsc28gaW4gcmVnZW4gMikKICAiUFJPWDEiLCAjIGRldmVsb3BpbmcgbGl2ZXIgbWFya2VyCiAgIkNPUEEiLCAjIHZlc2ljbGUgdHJhZmZpY2tpbmcgKGFsc28gaW4gcmVnZW4gMSkKICAiQ0RIMiIsICMgY2x1c3RlciA0CiAgIkNEMTUxIiwgIyBjbHVzdGVyIDQKICAgICAgICAgICAjIHJlZ2VuZXJhdGluZyBjbHVzdGVycwogICJBR1BBVDIiLCAjIGxpcGlkIG1ldGFib2xpc20KICAiQ09YNkMiLCAjIGVsZWN0cm9uIHRyYW5zcG9ydCBjaGFpbgogICJQVEdSMSIsICMgZmF0dHkgYWNpZCBtZXRhYm9saXNtCiAgIkZPWEEzIiwgIyBsaXZlciBkZXZlbG9wbWVudCAoY2x1c3RlciAxKQogICJGT1hPMSIsICMgY29udHJvbCBvZiBtZXRhYm9saXNtIGFuZCBDQyBhcnJlc3QKICAiQ1lQMkE2IiwgIyBjbHVzdGVyIDQKICAiQ1lQMkI2IiwgIyBjbHVzdGVyIDQKICAiQ1lQNEExMSIsICMgY2x1c3RlciA0CiAgIlNEQzQiLCAjIGNsdXN0ZXIgNAogICJTVEFUMSIsICMgY2x1c3RlciA0CiAgIyBub3JtYWwgem9uYXRpb24KICAiU0FBMSIsICJTQUEyIiwgIkhBTVAiLCAiQzMiLCAiQ1lQMkUxIiwiQ1lQMUEyIiwiSFVMQyIsIkJDSEUiLCJDWVAzQTQiLAogICJDUlAiLCAiU0RTIiwgIkhBTCIsICJJR0ZCUDEiLCAiSUdGQlAyIiwgIkJBQVQiLCAiU0xDTzFCMyIpCmBgYAoKYGBge3J9CmhlcF9kZiA9IGRhdGEuZnJhbWUodmFscyA9IGMoaGVwX2NlbGxzJGhlYWx0aHkkem9uYXRpb25fcHQsIGhlcF9jZWxscyRlbWJvbGlzZWQkem9uYXRpb25fcHQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhlcF9jZWxscyRyZWdlbmVyYXRpbmckem9uYXRpb25fcHQpLCAKICAgICAgICAgICAgICAgICAgICAgQ29uZGl0aW9uID0gYyhyZXAoImhlYWx0aHkiLCBsZW5ndGgoaGVwX2NlbGxzJGhlYWx0aHkkem9uYXRpb25fcHQpKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVwKCJlbWJvbGlzZWQiLCBsZW5ndGgoaGVwX2NlbGxzJGVtYm9saXNlZCR6b25hdGlvbl9wdCkpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXAoInJlZ2VuZXJhdGluZyIsIGxlbmd0aChoZXBfY2VsbHMkcmVnZW5lcmF0aW5nJHpvbmF0aW9uX3B0KSkpLAogICAgICAgICAgICAgICAgICAgICBEb25vciA9IGMoaGVwX2NlbGxzJGhlYWx0aHkkRG9ub3IsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGVwX2NlbGxzJGVtYm9saXNlZCREb25vciwgaGVwX2NlbGxzJHJlZ2VuZXJhdGluZyREb25vciksCiAgICAgICAgICAgICAgICAgICAgIGN0ID0gYyhoZXBfY2VsbHMkaGVhbHRoeSRhbGxjZWxsc19zaW1wLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhlcF9jZWxscyRlbWJvbGlzZWQkYWxsY2VsbHNfc2ltcCwgaGVwX2NlbGxzJHJlZ2VuZXJhdGluZyRhbGxjZWxsc19zaW1wKSkKaGVwX2RmJGJpbnMxMCA9IGN1dChoZXBfZGYkdmFscywgMTApCmhlcF9kZiRDb25kaXRpb24gPSBmYWN0b3IoaGVwX2RmJENvbmRpdGlvbiwgbGV2ZWxzID0gYygiaGVhbHRoeSIsICJlbWJvbGlzZWQiLCAicmVnZW5lcmF0aW5nIikpCmxldmVscyhoZXBfZGYkRG9ub3IpID0gYygic2NfRTEvUjEiLCAic2NfRTIvUjIiLCAic2NfRTMvUjMiLCAic2NfRTQvUjQiLCAic2NfRTUvUjUiLCAic2NfRTYvUjYiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICJzY19IMSIsICJzY19IMiIsICJzY19IMyIpCgpwbHRfZGlzdHMgPSBnZ3Bsb3QoaGVwX2RmLCBhZXMoeCA9IGJpbnMxMCwgZmlsbCA9IENvbmRpdGlvbikpKwogICAgIGZhY2V0X3dyYXAofkNvbmRpdGlvbikrCiAgICAgZ2VvbV9iYXIoKSsKICAgICBsYWJzKHggPSAiem9uYXRpb24gKGJpbm5lZCkiLCB5ID0gIk51bWJlciBvZiBjZWxscyIpKwogICAgIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBjKDAsMCkpKwogICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNvbGNvbmQpKwogICAgIGNvb3JkX2ZsaXAoKSsKICAgICBndWlkZXMoZmlsbCA9IGd1aWRlX2xlZ2VuZCh0aXRsZS5wb3NpdGlvbiA9ICJsZWZ0IikpKwogICAgIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgIGxlZ2VuZC50aXRsZS5hbGlnbiA9IDAsCiAgICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsCiAgICAgICAgICAgbGVnZW5kLmJveC5tYXJnaW4gPSBtYXJnaW4oMCwwLDAsMCksCiAgICAgICAgICAgbGVnZW5kLmJveC5zcGFjaW5nID0gdW5pdCgwLjA1LCAiY20iKSkKCnBkZigiZmlndXJlX3BhbmVscy9maWczL2hlcF96b25hdGlvbl9jb25kaXRpb25EaXN0LnBkZiIsIGhlaWdodCA9IDIuMywgd2lkdGggPSAzLjYsIHVzZURpbmdiYXRzID0gRikKcHJpbnQocGx0X2Rpc3RzKQpkZXYub2ZmKCkKYGBgCgpEb25vciBkZW5zaXR5IHBlciBjb25kaXRpb24KCmBgYHtyfQpoZXBfZG9uID0gZ2dwbG90KGhlcF9kZiwgYWVzKHggPSB2YWxzLCBjb2xvdXIgPSBEb25vcikpKwogICAgIGZhY2V0X3dyYXAofkNvbmRpdGlvbiwgc2NhbGVzID0gImZyZWVfeSIpKwogICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDApKwogICAgIGdlb21fZGVuc2l0eSgpKwogICAgIGxhYnMoeCA9ICJ6b25hdGlvbiIsIHkgPSAiY2VsbCBkZW5zaXR5IikrCiAgICAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwwKSkrCiAgICAgY29vcmRfZmxpcCgpKwogICAgIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9sZWdlbmQodGl0bGUucG9zaXRpb24gPSAibGVmdCIsIG5yb3cgPSAzKSkrCiAgICAgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgYXhpcy50aWNrcy54ID0gZWxlbWVudF9saW5lKCksCiAgICAgICAgICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChtYXJnaW4gPSBtYXJnaW4oMC4wNCwwLDAuMDQsMCwgImNtIiksIHNpemUgPSA3LjUpLAogICAgICAgICAgIGxlZ2VuZC50aXRsZS5hbGlnbiA9IDAsCiAgICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsCiAgICAgICAgICAgbGVnZW5kLmJveC5tYXJnaW4gPSBtYXJnaW4oMCwwLDAsMCksCiAgICAgICAgICAgbGVnZW5kLmJveC5zcGFjaW5nID0gdW5pdCgwLjA1LCAiY20iKSkKCnBkZigiZmlndXJlX3BhbmVscy9maWczL2hlcF96b25hdGlvbl9jb25kaXRpb25Eb25vcnMucGRmIiwgaGVpZ2h0ID0gMywgd2lkdGggPSAzLjYsIHVzZURpbmdiYXRzID0gRikKcHJpbnQoaGVwX2RvbikKZGV2Lm9mZigpCmBgYAoKWm9uYXRpb24gZ3JvdXBlZCBieSBkb25vcnMKCmBgYHtyfQpoZXBfZG9uID0gZ2dwbG90KGhlcF9kZiwgYWVzKHggPSB2YWxzLCBjb2xvdXIgPSBDb25kaXRpb24pKSsKICAgICBmYWNldF93cmFwKH5Eb25vciwgc2NhbGVzID0gImZyZWVfeSIpKwogICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDApKwogICAgIGdlb21fZGVuc2l0eSgpKwogICAgIGxhYnMoeCA9ICJ6b25hdGlvbiIsIHkgPSAiY2VsbCBkZW5zaXR5IikrCiAgICAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjb2xjb25kKSsKICAgICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLDApKSsKICAgICBjb29yZF9mbGlwKCkrCiAgICAgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2xlZ2VuZCh0aXRsZS5wb3NpdGlvbiA9ICJsZWZ0IiwgbmNvbCA9IDMpKSsKICAgICB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICBheGlzLnRpY2tzLnggPSBlbGVtZW50X2xpbmUoKSwKICAgICAgICAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KG1hcmdpbiA9IG1hcmdpbigwLjA0LDAsMC4wNCwwLCAiY20iKSwgc2l6ZSA9IDcuNSksCiAgICAgICAgICAgbGVnZW5kLnRpdGxlLmFsaWduID0gMCwKICAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwKICAgICAgICAgICBsZWdlbmQuYm94Lm1hcmdpbiA9IG1hcmdpbigwLDAsMCwwKSwKICAgICAgICAgICBsZWdlbmQuYm94LnNwYWNpbmcgPSB1bml0KDAuMDUsICJjbSIpKQoKcGRmKCJmaWd1cmVfcGFuZWxzL2ZpZzMvaGVwX3pvbmF0aW9uX0Rvbm9yc0NvbmQucGRmIiwgaGVpZ2h0ID0gMywgd2lkdGggPSAzLjYsIHVzZURpbmdiYXRzID0gRikKcHJpbnQoaGVwX2RvbikKZGV2Lm9mZigpCmBgYAoKSGVwIGJpbm5lZCB6b25hdGlvbiBub3JtYWxpc2VkIHRvIGhlYWx0aHkKCmBgYHtyfQpoZXBfZGYgPSBkYXRhLmZyYW1lKHZhbHMgPSBjKGhlcF9jZWxscyRoZWFsdGh5JHpvbmF0aW9uX3B0LCBoZXBfY2VsbHMkZW1ib2xpc2VkJHpvbmF0aW9uX3B0LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoZXBfY2VsbHMkcmVnZW5lcmF0aW5nJHpvbmF0aW9uX3B0KSwgCiAgICAgICAgICAgICAgICAgICAgIENvbmRpdGlvbiA9IGMocmVwKCJoZWFsdGh5IiwgbGVuZ3RoKGhlcF9jZWxscyRoZWFsdGh5JHpvbmF0aW9uX3B0KSksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlcCgiZW1ib2xpc2VkIiwgbGVuZ3RoKGhlcF9jZWxscyRlbWJvbGlzZWQkem9uYXRpb25fcHQpKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVwKCJyZWdlbmVyYXRpbmciLCBsZW5ndGgoaGVwX2NlbGxzJHJlZ2VuZXJhdGluZyR6b25hdGlvbl9wdCkpKSkKaGVwX2RmJGJpbnMxMCA9IGN1dChoZXBfZGYkdmFscywgMTApCmhlcF9kZiRDb25kaXRpb24gPSBmYWN0b3IoaGVwX2RmJENvbmRpdGlvbiwgbGV2ZWxzID0gYygiaGVhbHRoeSIsICJlbWJvbGlzZWQiLCAicmVnZW5lcmF0aW5nIikpCmhlcF9kZiA9IGRhdGEuZnJhbWUodGFibGUoaGVwX2RmJENvbmRpdGlvbiwgaGVwX2RmJGJpbnMxMCkpCmhlcF9kZiA9IGhlcF9kZltvcmRlcihoZXBfZGYkVmFyMSksXQpoZXBfZGYkRnJlcW5vcm0gPSB1bmxpc3QodGFwcGx5KGhlcF9kZiRGcmVxLCBoZXBfZGYkVmFyMSwgZnVuY3Rpb24oeCkgeC9zdW0oeCkpKQpoZXBfZGYkRnJlcW5vcm1faCA9IGhlcF9kZiRGcmVxbm9ybS9tZWFuKGhlcF9kZiRGcmVxbm9ybVtoZXBfZGYkVmFyMT09ImhlYWx0aHkiXSkKCnBsdF9kaXN0cyA9IGdncGxvdChoZXBfZGYsIGFlcyh4ID0gVmFyMiwgZmlsbCA9IFZhcjEsIHkgPSBGcmVxbm9ybV9oKSkrCiAgICAgZmFjZXRfd3JhcCh+VmFyMSkrCiAgICAgZ2VvbV9jb2woKSsKICAgICBsYWJzKHggPSAiem9uYXRpb24gKGJpbm5lZCkiLCB5ID0gIlByb3BvcnRpb24gb2YgY2VsbHMgKGNvbXBhcmVkIHRvIGhlYWx0aHkpIikrCiAgICAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwwKSwgbGFiZWxzID0gYygiMCIsICIwLjUiLCAiMSIsICIxLjUiLCAiMiIsICIyLjUiKSkrCiAgICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY29sY29uZCkrCiAgICAgY29vcmRfZmxpcCgpKwogICAgIGd1aWRlcyhmaWxsID0gZ3VpZGVfbGVnZW5kKHRpdGxlLnBvc2l0aW9uID0gImxlZnQiKSkrCiAgICAgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYpLAogICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKCnBkZigiZmlndXJlX3BhbmVscy9maWczL2hlcF96b25hdGlvbl9jb25kaXRpb25EaXN0X25vcm0ucGRmIiwgCiAgICBoZWlnaHQgPSAyLCB3aWR0aCA9IDMuOCwgdXNlRGluZ2JhdHMgPSBGKQpwcmludChwbHRfZGlzdHMpCmRldi5vZmYoKQpgYGAKClBsb3QgR08gVGVybXMgKGdlbmVyYWwpCgpgYGB7cn0KZ29fdGhlbWUgPSB0aGVtZV9idygpKwogIHRoZW1lKGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChjb2xvdXIgPSAiYmxhY2siLCBzaXplID0gNy41KSwKICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA4KSwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA5KSwKICAgICAgICBwbG90LnRpdGxlLnBvc2l0aW9uID0gInBsb3QiLAogICAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDcuNSksCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQodmp1c3QgPSAwLjYsIGNvbG91ciA9IGMoImdyZXk0NSIsICJncmV5MTciKSksCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvci55ID0gZWxlbWVudF9ibGFuaygpKQoKZ29wbHRGdW5jID0gZnVuY3Rpb24ocGxvdF9kZiwgdGl0ID0gIiIsIHN1YnRpdCA9ICIiKXsKICBwbG90X2RmJERlc2NyaXB0aW9uID0gYnJlYWtTdHIocGxvdF9kZiREZXNjcmlwdGlvbiwgMzApCiAgcGxvdF9kZiREZXNjcmlwdGlvbiA9IGZhY3RvcihwbG90X2RmJERlc2NyaXB0aW9uLCBsZXZlbHMgPSByZXYocGxvdF9kZiREZXNjcmlwdGlvbikpCiAgcGxvdF9kZiRmaWxsID0gYXMuY2hhcmFjdGVyKHJlcCgxOjIsIGNlaWxpbmcobnJvdyhwbG90X2RmKS8yKSkpWzE6bnJvdyhwbG90X2RmKV0KICBwbHQgPSBnZ3Bsb3QocGxvdF9kZiwgYWVzKHggPSAtbG9nMTAocXZhbHVlKSwgeSA9IERlc2NyaXB0aW9uLCBmaWxsID0gZmlsbCkpKwogICAgZ2VvbV9jb2woc2hvdy5sZWdlbmQgPSBGKSsKICAgIHNjYWxlX3hfY29udGludW91cyhleHBhbmQgPSBjKDAsMCksIGxpbSA9IGMoMCwgbWF4KC1sb2cxMChwbG90X2RmJHF2YWx1ZSkpKzEpKSsKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoImdyZXkxNyIsICJncmV5NDUiKSkrCiAgICBsYWJzKHRpdGxlID0gdGl0LCBzdWJ0aXRsZSA9IHN1YnRpdCkrCiAgICBnb190aGVtZQogIHJldHVybihwbHQpCn0KCnBkZigiZmlndXJlX3BhbmVscy9maWczL2hlcF9nb19lbWJfbm90Y29yci5wZGYiLCBoZWlnaHQgPSAzLjIsIHdpZHRoID0gMy42LCB1c2VEaW5nYmF0cyA9IEYpCnByaW50KGdvcGx0RnVuYyhoZXBfcmVzX2xpc3QkZW1ib2xpc2VkJGdvX2NsJGFsbCwgdGl0ID0gIkdPIFRlcm1zIC0gRW1ib2xpc2VkIiwgc3VidGl0ID0gImNvciA8IDAuMyIpKQpkZXYub2ZmKCkKCnBkZigiZmlndXJlX3BhbmVscy9maWczL2hlcF9nb19lbWJfY29yci5wZGYiLCBoZWlnaHQgPSAzLjIsIHdpZHRoID0gMy42LCB1c2VEaW5nYmF0cyA9IEYpCnByaW50KGdvcGx0RnVuYyhoZXBfcmVzX2xpc3QkZW1ib2xpc2VkJGdvX2NsJHBvcywgdGl0ID0gIkdPIFRlcm1zIC0gRW1ib2xpc2VkIiwgc3VidGl0ID0gImNvciA8IDAuMyIpKQpkZXYub2ZmKCkKCnBkZigiZmlndXJlX3BhbmVscy9maWczL2hlcF9nb19yZWdfbm90Y29yci5wZGYiLCBoZWlnaHQgPSAzLjIsIHdpZHRoID0gMy42LCB1c2VEaW5nYmF0cyA9IEYpCnByaW50KGdvcGx0RnVuYyhoZXBfcmVzX2xpc3QkcmVnZW5lcmF0aW5nJGdvX2NsJGFsbCwgdGl0ID0gIkdPIFRlcm1zIC0gUmVnZW5lcmF0aW5nIiwgc3VidGl0ID0gImNvciA+PSAwLjMiKSkKZGV2Lm9mZigpCgpwZGYoImZpZ3VyZV9wYW5lbHMvZmlnMy9oZXBfZ29fcmVnX2NvcnIucGRmIiwgaGVpZ2h0ID0gMy4yLCB3aWR0aCA9IDMuNiwgdXNlRGluZ2JhdHMgPSBGKQpwcmludChnb3BsdEZ1bmMoaGVwX3Jlc19saXN0JHJlZ2VuZXJhdGluZyRnb19jbCRwb3MsIHRpdCA9ICJHTyBUZXJtcyAtIFJlZ2VuZXJhdGluZyIsIHN1YnRpdCA9ICJjb3IgPj0gMC4zIikpCmRldi5vZmYoKQpgYGAKClBsb3QgR08gVGVybXMgKGVhY2ggY2x1c3RlcikKCmBgYHtyfQpwYXRoZ28gPSAiZmlndXJlX3BhbmVscy9maWczL2dvdGVybXNfY2x1c3RlcnMvIgpkaXIuY3JlYXRlKHBhdGhnbywgc2hvd1dhcm5pbmdzID0gRkFMU0UpCgpmb3IoY2MgaW4gbmFtZXMoaGVwX3Jlc19saXN0KSl7CiAgdGl0ID0gaWZlbHNlKGNjPT0iZW1ib2xpc2VkIiwgIkdPIFRlcm1zIC0gRW1ib2xpc2VkIiwgIkdPIFRlcm1zIC0gUmVnZW5lcmF0aW5nIikKICBmb3IobiBpbiAxOjUpewogICAgcGxvdF9kZiA9IGhlcF9yZXNfbGlzdFtbY2NdXSRnb19jbFtbYXMuY2hhcmFjdGVyKG4pXV0KICAgIGlmKG5yb3cocGxvdF9kZik+MCl7CiAgICAgIHBsdCA9IGdvcGx0RnVuYyhwbG90X2RmLCB0aXQgPSB0aXQsIHN1YnRpdCA9IHBhc3RlMCgiQ2x1c3RlciAiLCBuLCAiOyBjb3IgPCAwLjMiKSkKICAgICAgaWYobnJvdyhwbG90X2RmKSUlMj09MSl7CiAgICAgICAgcGx0ID0gcGx0ICsgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQodmp1c3QgPSAwLjYsIGNvbG91ciA9IGMoImdyZXkxNyIsImdyZXk0NSIpKSkKICAgICAgfQogICAgICBwZGYocGFzdGUwKHBhdGhnbywgImhlcF9nb18iLCBjYywgIl9jbCIsIG4sICIucGRmIiksIGhlaWdodCA9IDMuMiwgd2lkdGggPSAzLjYsIHVzZURpbmdiYXRzID0gRikKICAgICAgcHJpbnQocGx0KQogICAgICBkZXYub2ZmKCkKICAgIH0KICB9Cn0KYGBgCgpQbG90cyBmb3IgaW5kaXZpZHVhbCBnZW5lcwoKYGBge3J9CmdlbmVwbG90X3RoZW1lID0gdGhlbWVfYncoKSsKICAgIHRoZW1lKGFzcGVjdC5yYXRpbyA9IDEvMS41LAogICAgICAgICAgcGFuZWwuZ3JpZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChjb2xvdXIgPSAiYmxhY2siLCBzaXplID0gNyksCiAgICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA4KSwKICAgICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwLCBmYWNlID0gIml0YWxpYyIpLAogICAgICAgICAgcGxvdC50aXRsZS5wb3NpdGlvbiA9ICJwbG90IiwKICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLAogICAgICAgICAgbGVnZW5kLmJveC5tYXJnaW4gPSBtYXJnaW4oMCwwLDAsMCksCiAgICAgICAgICBsZWdlbmQuYm94LnNwYWNpbmcgPSB1bml0KDAuMDEsImNtIiksCiAgICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gOCksCiAgICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDkpKQoKcGx0X2dlbmVfbGlzdCA9IGxpc3QoKQpmb3IoZyBpbiBnX2xpc3QpewogIHBsdF9kZiA9IGRhdGEuZnJhbWUoImV4cCIgPSBjKGhlcF9zaWdfZml0cyRoZWFsdGh5WyxnXSwgaGVwX3NpZ19maXRzJGVtYm9saXNlZFssZ10pLAogICAgICAgICAgICAgICAgICAgICJjb25kIiA9IHJlcChjKCJoZWFsdGh5IiwgImVtYm9saXNlZCIpLCBlYWNoID0gMTAwKSwKICAgICAgICAgICAgICAgICAgICAidCIgPSByZXAoMToxMDAsIDIpKQogIHBsdF9kZiRjb25kID0gZmFjdG9yKHBsdF9kZiRjb25kLCBsZXZlbHMgPSBjKCJoZWFsdGh5IiwgImVtYm9saXNlZCIpKQogIHBsdGVtYiA9IGdncGxvdChwbHRfZGYsIGFlcyh4ID0gdCwgeSA9IGV4cCwgZ3JvdXAgPSBjb25kLCBjb2wgPSBjb25kKSkrCiAgICBnZW9tX2xpbmUoc2l6ZSA9IDEuNSkrCiAgICBsYWJzKHggPSAiem9uYXRpb24iLCB5ID0gIkV4cHJlc3Npb24iLCB0aXRsZSA9IGcpKwogICAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjb2xjb25kKSsKICAgIGdlbmVwbG90X3RoZW1lCiAgCiAgcGx0X2RmID0gZGF0YS5mcmFtZSgiZXhwIiA9IGMoaGVwX3NpZ19maXRzJGhlYWx0aHlbLGddLCBoZXBfc2lnX2ZpdHMkcmVnZW5lcmF0aW5nWyxnXSksCiAgICAgICAgICAgICAgICAgICAgImNvbmQiID0gcmVwKGMoImhlYWx0aHkiLCAicmVnZW5lcmF0aW5nIiksIGVhY2ggPSAxMDApLAogICAgICAgICAgICAgICAgICAgICJ0IiA9IHJlcCgxOjEwMCwgMikpCiAgcGx0X2RmJGNvbmQgPSBmYWN0b3IocGx0X2RmJGNvbmQsIGxldmVscyA9IGMoImhlYWx0aHkiLCAicmVnZW5lcmF0aW5nIikpCiAgcGx0cmVnID0gZ2dwbG90KHBsdF9kZiwgYWVzKHggPSB0LCB5ID0gZXhwLCBncm91cCA9IGNvbmQsIGNvbCA9IGNvbmQpKSsKICAgIGdlb21fbGluZShzaXplID0gMS41KSsKICAgIGxhYnMoeCA9ICJ6b25hdGlvbiIsIHkgPSAiRXhwcmVzc2lvbiIsIHRpdGxlID0gZykrCiAgICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGNvbGNvbmQpKwogICAgZ2VuZXBsb3RfdGhlbWUKICBwcmludChjb3dwbG90OjpwbG90X2dyaWQocGx0ZW1iLCBwbHRyZWcsIG5jb2wgPSAyKSkKICAKICBwbHRfZ2VuZV9saXN0W1tnXV0gPSBsaXN0KCJlbWJvbGlzZWQiID0gcGx0ZW1iLCAicmVnZW5lcmF0aW5nIiA9IHBsdHJlZykKfQpmb3IoZyBpbiBuYW1lcyhwbHRfZ2VuZV9saXN0KSl7CiAgZm9yKG4gaW4gbmFtZXMocGx0X2dlbmVfbGlzdFtbZ11dKSl7CiAgICBwZGYocGFzdGUwKCJmaWd1cmVfcGFuZWxzL2ZpZzMvaGVwX3pvbl8iLCBnLCAiXyIsICBuLCAiLnBkZiIpLCAKICAgICAgICBoZWlnaHQgPSAyLjIsIHdpZHRoID0gMi41LCB1c2VEaW5nYmF0cyA9IEYpCiAgICBwcmludChwbHRfZ2VuZV9saXN0W1tnXV1bW25dXSkKICAgIGRldi5vZmYoKQogIH0KfQpgYGAKClBsb3QgaW5kaXZpZHVhbCBnZW5lcyB3aXRoIGFsbCB0aHJlZSBjb25kaXRpb25zCgpgYGB7cn0KcGx0XzNfbGlzdCA9IGxpc3QoKQpmb3IoZyBpbiBnX2xpc3QpewogIHBsdF9kZiA9IGRhdGEuZnJhbWUoImV4cCIgPSBjKGhlcF9zaWdfZml0cyRoZWFsdGh5WyxnXSwgaGVwX3NpZ19maXRzJGVtYm9saXNlZFssZ10sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGVwX3NpZ19maXRzJHJlZ2VuZXJhdGluZ1ssZ10pLAogICAgICAgICAgICAgICAgICAgICJjb25kIiA9IHJlcChjKCJoZWFsdGh5IiwgImVtYm9saXNlZCIsICJyZWdlbmVyYXRpbmciKSwgZWFjaCA9IDEwMCksCiAgICAgICAgICAgICAgICAgICAgInQiID0gcmVwKDE6MTAwLCAzKSkKICBwbHRfZGYkY29uZCA9IGZhY3RvcihwbHRfZGYkY29uZCwgbGV2ZWxzID0gYygiaGVhbHRoeSIsICJlbWJvbGlzZWQiLCAicmVnZW5lcmF0aW5nIikpCiAgcGx0XzNfbGlzdFtbZ11dID0gZ2dwbG90KHBsdF9kZiwgYWVzKHggPSB0LCB5ID0gZXhwLCBncm91cCA9IGNvbmQsIGNvbCA9IGNvbmQpKSsKICAgIGdlb21fbGluZShzaXplID0gMS41KSsKICAgIGxhYnMoeCA9ICJ6b25hdGlvbiIsIHkgPSAiRXhwcmVzc2lvbiIsIHRpdGxlID0gZywgY29sb3VyID0gIkNvbmRpdGlvbiIpKwogICAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjb2xjb25kKSsKICAgIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9sZWdlbmQodGl0bGUucG9zaXRpb24gPSAidG9wIikpKwogICAgZ2VuZXBsb3RfdGhlbWUKfQoKZm9yKGcgaW4gbmFtZXMocGx0XzNfbGlzdCkpewogIHBkZihwYXN0ZTAoImZpZ3VyZV9wYW5lbHMvZmlnMy9oZXBfem9uXyIsIGcsICJfYWxsLnBkZiIpLCAKICAgICAgaGVpZ2h0ID0gMi41LCB3aWR0aCA9IDMsIHVzZURpbmdiYXRzID0gRikKICBwcmludChwbHRfM19saXN0W1tnXV0pCiAgZGV2Lm9mZigpCn0KYGBgCgpQbG90IG1lYW4gcHJvZmlsZXMKCmBgYHtyfQpmb3IobiBpbiBuYW1lcyhoZXBfcmVzX2xpc3QpKXsKICBwbG90X2RmMiA9IGhlcF9yZXNfbGlzdFtbbl1dJGRmCiAgeHh4ID0gcGxvdF9kZjJbcGxvdF9kZjIkY29uZD09ImRpZmZlcmVuY2UiLF0KICBsYWJzZGYgPSBkYXRhLmZyYW1lKGxhYnMgPSBjKCJoaWdoZXIgaW5cbmhlYWx0aHkiLCBwYXN0ZTAoImhpZ2hlciBpblxuIiwgbikpLCBjb29yZCA9IGMoMC41LCAtMC41KSkKICBwbHQxID0gZ2dwbG90KHh4eCwgYWVzKHggPSBWYXIxLCB5ID0gdmFsdWUpKSsKICAgICAgZmFjZXRfZ3JpZCh+Y2xzLCBzY2FsZXMgPSAiZnJlZSIpKwogICAgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBjb2xvdXIgPSAiZ3JleTYwIiwgc2l6ZSA9IDAuNzUsIGxpbmV0eXBlID0gImRhc2hlZCIpKwogICAgICBzdGF0X3N1bW1hcnkoZnVuLmRhdGE9bWVhbl9jbF9ib290LCBjb2xvdXI9ImdyZXk0MCIsIGFscGhhID0gMC4zNSwgZ2VvbT0ibGluZXJhbmdlIiwgZ3JvdXA9MSkrCiAgICAgIHN0YXRfc3VtbWFyeShmdW49bWVhbiwgY29sb3VyPSJibGFjayIsIGdlb209ImxpbmUiLCBncm91cD0xKSsKICAgICAgbGFicyh4ID0gInpvbmF0aW9uIiwgeSA9ICJkaWZmZXJlbmNlIGluXG5zY2FsZWQgZXhwcmVzc2lvbiIpKwogICAgICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygtMSwxKSkrCiAgICAgIHRoZW1lX2J3KCkrCiAgICAgIHRoZW1lKGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChjb2xvdXIgPSAiYmxhY2siLCBzaXplID0gNyksCiAgICAgICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpKQogIHBsdDIgPSBnZ3Bsb3QoKSsKICAgIGdlb21fdGV4dChkYXRhID0gbGFic2RmLCBtYXBwaW5nID0gYWVzKHkgPSBjb29yZCwgbGFiZWwgPSBsYWJzKSwgCiAgICAgICAgICAgICAgeCA9IDAuNSwgYW5nbGUgPSAyNzAsIHNpemUgPSAzKSsKICAgIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKDAsMSkpKwogICAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMoLTEsMSkpKwogICAgY293cGxvdDo6dGhlbWVfbm90aGluZygpCiAgcGx0ID0gY293cGxvdDo6cGxvdF9ncmlkKHBsdDEsIHBsdDIsIG5jb2wgPSAyLCBucm93ID0gMSwgcmVsX3dpZHRocyA9IGMoMSwgMC4wODUpLCBhbGlnbiA9ICJodiIpCiAgCiAgcGRmKHBhc3RlMCgiZmlndXJlX3BhbmVscy9maWczL2hlcF96b25fIiwgbiwgIl9tZWFuLnBkZiIpLCBoZWlnaHQgPSAxLjgsIHdpZHRoID0gNiwgdXNlRGluZ2JhdHMgPSBGKQogIHByaW50KHBsdCkKICBkZXYub2ZmKCkKfQpgYGAKClBsb3QgaGVhdG1hcHMKCmBgYHtyLCBmaWcud2lkdGg9My44LCBmaWcuaGVpZ2h0PTIuNX0KIyBnZXQgcHJvZmlsZXMgZm9yIHBsb3R0aW5nCnVzZWdlbmVzID0gdW5pcXVlKGMoYXMuY2hhcmFjdGVyKGhlcF9yZXNfbGlzdCRlbWJvbGlzZWQkZGYkVmFyMiksCiAgICAgICAgICAgICAgICAgICAgYXMuY2hhcmFjdGVyKGhlcF9yZXNfbGlzdCRyZWdlbmVyYXRpbmckZGYkVmFyMikpKQoKYmluc19saXN0ID0gbGlzdCgpCmZvcihuIGluIG5hbWVzKGhlcF9jZWxscykpewogIHBsb3RfZGYgPSBjYmluZChkYXRhLmZyYW1lKCJwdCIgPSByZXAoMToxMCwgZWFjaCA9IDEwKSksaGVwX3NpZ19maXRzW1tuXV1bLHVzZWdlbmVzXSkKICBwbG90X2RmJGJpbnMxMCA9IGN1dChwbG90X2RmJHB0LCAxMCkKICBiaW5zX2xpc3RbW25dXSA9IHNhcHBseSh1c2VnZW5lcywgZnVuY3Rpb24oeCkgc2NhbGUodGFwcGx5KHBsb3RfZGZbLHhdLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBsb3RfZGYkYmluczEwLCBtZWFuKSlbMTA6MV0pCn0KYmluc19tZWFuID0gUmVkdWNlKHJiaW5kLCBiaW5zX2xpc3QpCmNvbG5hbWVzKGJpbnNfbWVhbikgPSB1c2VnZW5lcwoKIyBjaG9vc2UgZ2VuZXMgZm9yIHBsb3R0aW5nCmVjbF9nZW5lcyA9IG1lcmdlKHVuaXF1ZShoZXBfcmVzX2xpc3QkZW1ib2xpc2VkJGRmWyxjKDEsNCldKSwgaGVwX2ZpdHNfcXZhbCRlbWJvbGlzZWQkZmRyLCAKICAgICAgICAgICAgICAgICAgYnkueCA9IDEsICBieS55ID0gMCkKdG9wX2UgPSBlY2xfZ2VuZXMgJT4lIGdyb3VwX2J5KGNscykgJT4lIHNsaWNlX21pbihvcmRlcl9ieSA9IHB2YWxfbGlzdCwgbiA9IDUpCmVtYl9oZWF0ID0gcGhlYXRtYXAoYmluc19tZWFuWzE6MjAsYXMuY2hhcmFjdGVyKHRvcF9lJFZhcjIpXSwgc2hvd19yb3duYW1lcyA9IEYsIAogICAgICAgICAgICAgICAgICAgIGZvbnRzaXplX2NvbCA9IDYuMiwgYm9yZGVyX2NvbG9yID0gTkEsIGdhcHNfcm93ID0gYygxMCwyMCksIGdhcHNfY29sID0gc2VxKDUsIDIwLCA1KSwgCiAgICAgICAgICAgICAgICAgICAgY2x1c3RlcmluZ19tZXRob2QgPSAid2FyZC5EMiIsIGNsdXN0ZXJfcm93cyA9IEYsIGNsdXN0ZXJfY29scyA9IEYsIGZvbnRzaXplID0gNikKcGRmKCJmaWd1cmVfcGFuZWxzL2ZpZzMvaGVhdG1hcF96b25hdGlvbl9lbWIucGRmIiwgaGVpZ2h0PTIuNSwgd2lkdGg9My44LCB1c2VEaW5nYmF0cyA9IEYpCnByaW50KGVtYl9oZWF0KQpkZXYub2ZmKCkKd3JpdGUuY3N2KGVjbF9nZW5lcywgZmlsZSA9ICJmaWd1cmVfcGFuZWxzL2ZpZzMvaGVwX2VtYm9saXNlZF9jbHVzdGVyc19mZHIuY3N2Iiwgcm93Lm5hbWVzID0gRiwgcXVvdGUgPSBGKQoKcmNsX2dlbmVzID0gbWVyZ2UodW5pcXVlKGhlcF9yZXNfbGlzdCRyZWdlbmVyYXRpbmckZGZbLGMoMSw0KV0pLCBoZXBfZml0c19xdmFsJHJlZ2VuZXJhdGluZyRmZHIsIAogICAgICAgICAgICAgICAgICBieS54ID0gMSwgIGJ5LnkgPSAwKQp0b3BfciA9IHJjbF9nZW5lcyAlPiUgZ3JvdXBfYnkoY2xzKSAlPiUgc2xpY2VfbWluKG9yZGVyX2J5ID0gcHZhbF9saXN0LCBuID0gNSkKcmVnX2hlYXQgPSBwaGVhdG1hcChiaW5zX21lYW5bYygxOjEwLCAyMTozMCksYXMuY2hhcmFjdGVyKHRvcF9yJFZhcjIpXSwgc2hvd19yb3duYW1lcyA9IEYsIAogICAgICAgICAgICAgICAgICAgIGZvbnRzaXplX2NvbCA9IDcuNSwgYm9yZGVyX2NvbG9yID0gTkEsIGdhcHNfcm93ID0gYygxMCwyMCksIGdhcHNfY29sID0gc2VxKDUsIDIwLCA1KSwgCiAgICAgICAgICAgICAgICAgICAgY2x1c3RlcmluZ19tZXRob2QgPSAid2FyZC5EMiIsIGNsdXN0ZXJfcm93cyA9IEYsIGNsdXN0ZXJfY29scyA9IEYsIGZvbnRzaXplID0gNi43KQpwZGYoImZpZ3VyZV9wYW5lbHMvZmlnMy9oZWF0bWFwX3pvbmF0aW9uX3JlZy5wZGYiLCBoZWlnaHQ9Mi41LCB3aWR0aD0zLjgsIHVzZURpbmdiYXRzID0gRikKcHJpbnQocmVnX2hlYXQpCmRldi5vZmYoKQp3cml0ZS5jc3YocmNsX2dlbmVzLCBmaWxlID0gImZpZ3VyZV9wYW5lbHMvZmlnMy9oZXBfcmVnZW5fY2x1c3RlcnNfZmRyLmNzdiIsIHJvdy5uYW1lcyA9IEYsIHF1b3RlID0gRikKYGBgCgoKCiMgRmlndXJlIDQKIyMgTWFpbiBGaWd1cmUKTG9hZCBkYXRhCgpgYGB7cn0Kb25seV9lbmRfY2VsbHMgPSByZWFkUkRTKGZpbGUgPSAicmVzdWx0cy9lbmRvdGhlbGlhbC9vbmx5X2VuZF9jZWxsc196b24uUkRTIikKYWxsX2Nvcl9lbmQgPSByZWFkLmNzdigicmVzdWx0cy9lbmRvdGhlbGlhbC9jb3JyZWxhdGlvbnNfem9uYXRpb25fZW5kb3RoZWxpYWwuY3N2IiwgCiAgICAgICAgICAgICAgICAgICAgICAgaGVhZGVyID0gVCwgcm93Lm5hbWVzID0gMSkKZW5kX2ZpdHNfcXZhbCA9IHJlYWRSRFMoZmlsZSA9ICJyZXN1bHRzL2VuZG90aGVsaWFsL2VuZF9maXRzX3F2YWwuUkRTIikKbWtzaW1wID0gcmVhZC5jc3YoInJlc3VsdHMvZW5kb3RoZWxpYWwvbWFya2Vyc19lbmRvX3N1YnBvcF9zaW1wLmNzdiIsIGhlYWRlciA9IFQsIHJvdy5uYW1lcyA9IDEpCm1rc2ltcCA9IG1rc2ltcFtvcmRlcihta3NpbXAkYXZnX2xvZ0ZDLCBkZWNyZWFzaW5nID0gVCksXQoKdG9wX2dlbmVzID0gcmVhZFJEUyhmaWxlID0gInJlc3VsdHMvY29uZF9lZmZlY3QvdG9wX2dlbmVzX21rLlJEUyIpCgpnb19lbmQgPSByZWFkUkRTKCJyZXN1bHRzL2VuZG90aGVsaWFsL0dPVGVybXNfY29ycmVsYXRpb25zLlJEUyIpCgplbmRvX2NvbCA9IGMoIlBlcmlwb3J0YWwgTFNFQyIgPSAiYXF1YW1hcmluZTIiLCAgIk1pZHpvbmFsIExTRUMiID0gImFxdWFtYXJpbmUzIiwKICAgICAgICAgICAgICJQZXJpY2VudHJhbCBMU0VDIiA9ICJhcXVhbWFyaW5lNCIsICJMU0VDIChmZW5lc3RyLikiID0gImRhcmtzbGF0ZWdyYXkxIiwKICAgICAgICAgICAgICJMU0VDIChyZW1vZGVsbGluZykiID0gImN5YW40IiwgIkxTRUMgKGludGVyZmVyb24pIiA9ICJkYXJrc2xhdGVibHVlIiwKICAgICAgICAgICAgICJMU0VDIChoaWdoIE1UIDEpIiA9ICJibHVldmlvbGV0IiwgIkxTRUMgKGhpZ2ggTVQgMikiID0gImRhcmt2aW9sZXQiLAogICAgICAgICAgICAgIkxTRUMgKHN0cmVzcykiID0gImxpZ2h0Ymx1ZSIsICJFQyBub24tTFNFQyIgPSAiZm9yZXN0Z3JlZW4iLCAKICAgICAgICAgICAgICJMeW1waGF0aWMgRUMiID0gImNoYXJ0cmV1c2UzIiwgIkN5Y2xpbmcgY2VsbHMiID0gImdyZXkyMCIpCmBgYAoKVU1BUHMKCmBgYHtyLCBmaWcuaGVpZ2h0PTIuMiwgZmlnLndpZHRoPTMuNn0KZW5kb19jb2wgPSBjKCJQZXJpcG9ydGFsIExTRUMiID0gImFxdWFtYXJpbmUyIiwgICJNaWR6b25hbCBMU0VDIiA9ICJhcXVhbWFyaW5lMyIsCiAgICAgICAgICAgICAiUGVyaWNlbnRyYWwgTFNFQyIgPSAiYXF1YW1hcmluZTQiLCAiTFNFQyAoZmVuZXN0ci4pIiA9ICJkYXJrc2xhdGVncmF5MSIsCiAgICAgICAgICAgICAiTFNFQyAocmVtb2RlbGxpbmcpIiA9ICJjeWFuNCIsICJMU0VDIChpbnRlcmZlcm9uKSIgPSAiZGFya3NsYXRlYmx1ZSIsCiAgICAgICAgICAgICAiTFNFQyAoaGlnaCBNVCAxKSIgPSAiYmx1ZXZpb2xldCIsICJMU0VDIChoaWdoIE1UIDIpIiA9ICJkYXJrdmlvbGV0IiwKICAgICAgICAgICAgICJMU0VDIChzdHJlc3MpIiA9ICJsaWdodGJsdWUiLCAiRUMgbm9uLUxTRUMiID0gImZvcmVzdGdyZWVuIiwgCiAgICAgICAgICAgICAiTHltcGhhdGljIEVDIiA9ICJjaGFydHJldXNlMyIsICJDeWNsaW5nIGNlbGxzIiA9ICJncmV5MjAiKQoKcGxvdF9kZiA9IGNiaW5kKG9ubHlfZW5kX2NlbGxzQG1ldGEuZGF0YVssYygiZW5kb19zaW1wIiwgIkNvbmRpdGlvbiIsICJEb25vciIpXSwKICAgICAgICAgICAgICAgIG9ubHlfZW5kX2NlbGxzQHJlZHVjdGlvbnMkdW1hcEBjZWxsLmVtYmVkZGluZ3MpCnBsb3RfZGYkQ29uZGl0aW9uID0gZmFjdG9yKHBsb3RfZGYkQ29uZGl0aW9uLCBsZXZlbHMgPSBjKCJoZWFsdGh5IiwgImVtYm9saXNlZCIsICJyZWdlbmVyYXRpbmciKSkKcGxvdF9kZiRlbmRvX3NpbXAgPSBmYWN0b3IocGxvdF9kZiRlbmRvX3NpbXAsIGxldmVscyA9IG5hbWVzKGVuZG9fY29sKSkKcGxvdF9kZiREb25vciA9IHBseXI6OnJldmFsdWUocGxvdF9kZiREb25vciwgYygiSEQxIiA9ICJzY19IMSIsICJIRDIiID0gInNjX0gyIiwgIkhEMyIgPSAic2NfSDMiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiREQxIiA9ICJzY19FMS9zY19SMSIsICJERDIiID0gInNjX0UyL3NjX1IyIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkREMyIgPSAic2NfRTMvc2NfUjMiLCAiREQ1IiA9ICJzY19FNC9zY19SNCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJERDYiID0gInNjX0U1L3NjX1I1IiwgIkRENyIgPSAic2NfRTYvc2NfUjYiKSkKcGxvdF9kZiREb25vciA9IGZhY3RvcihwbG90X2RmJERvbm9yLCBsZXZlbHMgPSBjKCJzY19IMSIsICJzY19IMiIsICJzY19IMyIsICJzY19FMS9zY19SMSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAic2NfRTIvc2NfUjIiLCAic2NfRTMvc2NfUjMiLCAic2NfRTQvc2NfUjQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJzY19FNS9zY19SNSIsICJzY19FNi9zY19SNiIpKQpzZXQuc2VlZCgxKQpwbG90X2RmID0gcGxvdF9kZltzYW1wbGUoMTpucm93KHBsb3RfZGYpLCBzaXplID0gbnJvdyhwbG90X2RmKSwgcmVwbGFjZSA9IEYpLF0KCnBsdF9zdWJ0eXBlcyA9IGdncGxvdChwbG90X2RmLCBhZXMoeCA9IFVNQVBfMSwgeSA9IFVNQVBfMiwgY29sb3VyID0gZW5kb19zaW1wKSkrCiAgZ2VvbV9wb2ludChzaXplID0gMC4xKSsKICBndWlkZXMoY29sb3VyID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZSA9IDEuNzUpKSkrCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBlbmRvX2NvbCkrCiAgdGhlbWUoYXNwZWN0LnJhdGlvID0gMSwKICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpLAogICAgICAgIGxlZ2VuZC5ib3guc3BhY2luZyA9IHVuaXQoMC4wMSwgImNtIiksCiAgICAgICAgYXhpcy5saW5lID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQoKcGx0X2NvbmQgPSBnZ3Bsb3QocGxvdF9kZiwgYWVzKHggPSBVTUFQXzEsIHkgPSBVTUFQXzIsIGNvbG91ciA9IENvbmRpdGlvbikpKwogIGdlb21fcG9pbnQoc2l6ZSA9IDAuMSkrCiAgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KHNpemUgPSAxLjc1KSkpKwogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gY29sY29uZCkrCiAgdGhlbWUoYXNwZWN0LnJhdGlvID0gMSwKICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpLAogICAgICAgIGxlZ2VuZC5ib3guc3BhY2luZyA9IHVuaXQoMC4wMSwgImNtIiksCiAgICAgICAgYXhpcy5saW5lID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQoKcGx0X2RvbiA9IGdncGxvdChwbG90X2RmLCBhZXMoeCA9IFVNQVBfMSwgeSA9IFVNQVBfMiwgY29sb3VyID0gRG9ub3IpKSsKICBnZW9tX3BvaW50KHNpemUgPSAwLjEpKwogIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gMS43NSkpKSsKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGNvbGRvbmFsbCkrCiAgdGhlbWUoYXNwZWN0LnJhdGlvID0gMSwKICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpLAogICAgICAgIGxlZ2VuZC5ib3guc3BhY2luZyA9IHVuaXQoMC4wMSwgImNtIiksCiAgICAgICAgYXhpcy5saW5lID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQoKcGRmKCJmaWd1cmVfcGFuZWxzL2ZpZ19lbmRvL3VtYXBfY2x1c3RlcnMucGRmIiwgaGVpZ2h0PTIuMiwgd2lkdGg9My42LCB1c2VEaW5nYmF0cyA9IEYpCnByaW50KHBsdF9zdWJ0eXBlcykKZGV2Lm9mZigpCnBkZigiZmlndXJlX3BhbmVscy9maWdfZW5kby91bWFwX2NvbmQucGRmIiwgaGVpZ2h0PTIuMiwgd2lkdGg9My42LCB1c2VEaW5nYmF0cyA9IEYpCnByaW50KHBsdF9jb25kKQpkZXYub2ZmKCkKcGRmKCJmaWd1cmVfcGFuZWxzL2ZpZ19lbmRvL3VtYXBfZG9ub3JzLnBkZiIsIGhlaWdodD0yLjIsIHdpZHRoPTMuNiwgdXNlRGluZ2JhdHMgPSBGKQpwcmludChwbHRfZG9uKQpkZXYub2ZmKCkKCnBuZygiZmlndXJlX3BhbmVscy9maWdfZW5kby91bWFwX2NsdXN0ZXJzLnBuZyIsIGhlaWdodD02LjI1LCB3aWR0aD02LjI1LCB1bml0PSJjbSIsIAogICAgcmVzPTYwMCwgYW50aWFsaWFzID0gInN1YnBpeGVsIikKcHJpbnQocGx0X3N1YnR5cGVzK3RoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikpCmRldi5vZmYoKQpwbmcoImZpZ3VyZV9wYW5lbHMvZmlnX2VuZG8vdW1hcF9jb25kLnBuZyIsIGhlaWdodD02LjI1LCB3aWR0aD02LjI1LCB1bml0PSJjbSIsIAogICAgcmVzPTYwMCwgYW50aWFsaWFzID0gInN1YnBpeGVsIikKcHJpbnQocGx0X2NvbmQrdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSkKZGV2Lm9mZigpCnBuZygiZmlndXJlX3BhbmVscy9maWdfZW5kby91bWFwX2Rvbm9ycy5wbmciLCBoZWlnaHQ9Ni4yNSwgd2lkdGg9Ni4yNSwgdW5pdD0iY20iLCAKICAgIHJlcz02MDAsIGFudGlhbGlhcyA9ICJzdWJwaXhlbCIpCnByaW50KHBsdF9kb24rdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSkKZGV2Lm9mZigpCmBgYAoKRnJlcXVlbmN5IHRhYmxlcwoKYGBge3IsIGZpZy53aWR0aD0zLCBmaWcuaGVpZ2h0PTN9CmRmX2NudCA9IHRhYmxlKG9ubHlfZW5kX2NlbGxzJGVuZG9fc2ltcCwgb25seV9lbmRfY2VsbHMkQ29uZGl0aW9uKQpkZl9jbnRfcGVyQ29uZCA9IHJlc2hhcGUyOjptZWx0KGFwcGx5KGRmX2NudCwgMiwgZnVuY3Rpb24oeCkgcm91bmQoeC9zdW0oeCkqMTAwLCAxKSkpCmRmX2NudF9wZXJDbCA9IHJlc2hhcGUyOjptZWx0KGFwcGx5KGRmX2NudCwgMSwgZnVuY3Rpb24oeCkgcm91bmQoeC9zdW0oeCkqMTAwLCAxKSkpCgptYXRfY250X2FsbCA9IHJlc2hhcGUyOjpkY2FzdChkYXRhID0gZGZfY250X3BlckNsLCBmb3JtdWxhID0gVmFyMSB+IFZhcjIsIHZhbHVlLnZhciA9ICJ2YWx1ZSIpCnJvd25hbWVzKG1hdF9jbnRfYWxsKSA9IG1hdF9jbnRfYWxsJFZhcjEKbWF0X2NudF9hbGwgPSB0KG1hdF9jbnRfYWxsWywtMV0pCmN0b3JkID0gaGNsdXN0KGRpc3QobWF0X2NudF9hbGxbLGMoMiwxLDMpXSkpJG9yZGVyCgpoZWF0cCA9IHBoZWF0bWFwOjpwaGVhdG1hcChtYXRfY250X2FsbFtjdG9yZCxjKDIsMSwzKV0sIGNsdXN0ZXJfY29scyA9IEYsIGNsdXN0ZXJfcm93cyA9IEYsIAogICAgICAgICAgICAgICAgICAgICAgICAgICB0cmVlaGVpZ2h0X3JvdyA9IEYsIGRpc3BsYXlfbnVtYmVycyA9IFQsIGZvbnRzaXplX251bWJlciA9IDcsIAogICAgICAgICAgICAgICAgICAgICAgICAgICBudW1iZXJfY29sb3IgPSBjKCJibGFjayIsICJ3aGl0ZSIpW2FzLmludGVnZXIobWF0X2NudF9hbGxbY3RvcmQsYygyLDEsMyldPjUwKSsxXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSBjb2xvclJhbXBQYWxldHRlKGJyZXdlci5wYWwobiA9IDksIG5hbWUgPSAiQmx1ZXMiKSkoMTAwKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9udHNpemVfcm93ID0gNy41LCBmb250c2l6ZV9jb2wgPSA3LjUsIGFuZ2xlX2NvbCA9IDApCgpwZGYoImZpZ3VyZV9wYW5lbHMvZmlnX2VuZG8vY2x1c3Rlcl9wcm9wb3J0aW9uX2NvbmQucGRmIiwgaGVpZ2h0PTMuMiwgd2lkdGg9My4zLCB1c2VEaW5nYmF0cyA9IEYpCnByaW50KGhlYXRwKQpkZXYub2ZmKCkKYGBgCgpNYXJrZXJzCgpgYGB7cn0KbWtwbG90ID0gYygiTUdQIiwgIkFRUDEiLCAiQ0xFQzE0QSIsICJFRE5SQiIsICJDTEVDMUIiLCAiQ0xFQzRHIiwgIlBMVkFQIiwgCiAgICAgICAgICAgIlJCUDciLCAiQU5HUFQyIiwgIkNUR0YiLCAiSVNHMTUiLCAiSUZJVDMiLCAiTVJPIiwgIkVHUjEiLCJQVEdEUyIsICJJTk1UIiwgCiAgICAgICAgICAgIlBST1gxIiwgIkNDTDIxIiwgIlRPUDJBIikKbWtwbG90ID0gYygiTUdQIiwgIkFRUDEiLCAiQ0xFQzE0QSIsICJJR0ZCUDciLCAiQ0xFQzFCIiwgIkNMRUM0RyIsICJQTFZBUCIsIAogICAgICAgICAgICJSQlA3IiwgIkFOR1BUMiIsICJDVEdGIiwgIklTRzE1IiwgIklGSVQzIiwgIk1STyIsICJFR1IxIiwiUFRHRFMiLCAiSU5NVCIsIAogICAgICAgICAgICJQUk9YMSIsICJDQ0wyMSIsICJUT1AyQSIpCgpleHBkZiA9IHJlc2hhcGUyOjptZWx0KGNiaW5kKGRhdGEuZnJhbWUoTWF0cml4Ojp0KG9ubHlfZW5kX2NlbGxzQGFzc2F5cyRTQ1RAZGF0YVtta3Bsb3QsXSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiZW5kb19zaW1wIiA9IG9ubHlfZW5kX2NlbGxzJGVuZG9fc2ltcCkpKQpleHBkZiRlbmRvX3NpbXAgPSBmYWN0b3IoZXhwZGYkZW5kb19zaW1wLCBsZXZlbHMgPSBuYW1lcyhlbmRvX2NvbCkpCgp2aW9wbHQgPSBnZ3Bsb3QoZXhwZGYsIGFlcyh4ID0gZW5kb19zaW1wLCB5ID0gdmFsdWUsIGZpbGwgPSBlbmRvX3NpbXApKSsKICBmYWNldF9ncmlkKHZhcmlhYmxlfi4sIHNjYWxlcyA9ICJmcmVlX3kiKSsKICBnZW9tX3Zpb2xpbihzY2FsZSA9ICJ3aWR0aCIsIGNvbG91ciA9ICJncmV5ODIiLCBzaXplID0gMC4zNSkrCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gZW5kb19jb2wpKwogIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBjKDAsIDIsIDQpKSsKICBsYWJzKHkgPSAiRXhwcmVzc2lvbiIpKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IC0zMCwgaGp1c3QgPSAwLCB2anVzdCA9IDAuOSksCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSA2LjUpLAogICAgICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2xpbmUoKSwKICAgICAgICBzdHJpcC50ZXh0LnkgPSBlbGVtZW50X3RleHQoYW5nbGUgPSAwLCBzaXplID0gNywgbWFyZ2luID0gbWFyZ2luKDAsMCwwLDApKSwKICAgICAgICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJ3aGl0ZSIsIGZpbGwgPSAid2hpdGUiKSkKCnBkZigiZmlndXJlX3BhbmVsc19yZXYxL2ZpZ19lbmRvL3Zpb2xpbnNfbWtfMi5wZGYiLCBoZWlnaHQ9NS44LCB3aWR0aD0zLjQsIHVzZURpbmdiYXRzID0gRikKcHJpbnQodmlvcGx0KQpkZXYub2ZmKCkKCmJveHBsdCA9IGdncGxvdChleHBkZiwgYWVzKHggPSBlbmRvX3NpbXAsIHkgPSB2YWx1ZSwgZmlsbCA9IGVuZG9fc2ltcCkpKwogIGZhY2V0X2dyaWQodmFyaWFibGV+Liwgc2NhbGVzID0gImZyZWVfeSIpKwogIGdlb21fYm94cGxvdChjb2xvdXIgPSAiZ3JleTUwIiwgb3V0bGllci5zaGFwZSA9IE5BLCBzaXplID0gMC4yNSkrCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gZW5kb19jb2wpKwogIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBjKDAsIDIsIDQpKSsKICBsYWJzKHkgPSAiRXhwcmVzc2lvbiIpKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IC0zMCwgaGp1c3QgPSAwLCB2anVzdCA9IDAuOSksCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSA2LjUpLAogICAgICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2xpbmUoKSwKICAgICAgICBzdHJpcC50ZXh0LnkgPSBlbGVtZW50X3RleHQoYW5nbGUgPSAwLCBzaXplID0gNywgbWFyZ2luID0gbWFyZ2luKDAsMCwwLDApKSwKICAgICAgICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJ3aGl0ZSIsIGZpbGwgPSAid2hpdGUiKSkKCnBkZigiZmlndXJlX3BhbmVsc19yZXYxL2ZpZ19lbmRvL2JveGVzX21rXzIucGRmIiwgaGVpZ2h0PTUuOCwgd2lkdGg9My40LCB1c2VEaW5nYmF0cyA9IEYpCnByaW50KGJveHBsdCkKZGV2Lm9mZigpCmBgYAoKQmlubmVkIHpvbmF0aW9uCgpgYGB7cn0KcGxvdF9kZiA9IG9ubHlfZW5kX2NlbGxzQG1ldGEuZGF0YVtvbmx5X2VuZF9jZWxsc0BtZXRhLmRhdGEkZW5kb19zaW1wICVpbiUgYygiUGVyaXBvcnRhbCBMU0VDIiwgIk1pZHpvbmFsIExTRUMiLCAiUGVyaWNlbnRyYWwgTFNFQyIpICYgb25seV9lbmRfY2VsbHNAbWV0YS5kYXRhJGdvb2RjbCxdCnBsb3RfZGYkYmluczEwMCA9IGN1dChwbG90X2RmJHpvbmF0aW9uX3B0LCAxMCkKcGxvdF9kZiRDb25kaXRpb24gPSBmYWN0b3IocGxvdF9kZiRDb25kaXRpb24sIGxldmVscyA9IGMoImhlYWx0aHkiLCAiZW1ib2xpc2VkIiwgInJlZ2VuZXJhdGluZyIpKQplbmRfZGYgPSBkYXRhLmZyYW1lKHRhYmxlKHBsb3RfZGYkQ29uZGl0aW9uLCBwbG90X2RmJGJpbnMxMCkpCmVuZF9kZiA9IGVuZF9kZltvcmRlcihlbmRfZGYkVmFyMSksXQplbmRfZGYkRnJlcW5vcm0gPSB1bmxpc3QodGFwcGx5KGVuZF9kZiRGcmVxLCBlbmRfZGYkVmFyMSwgZnVuY3Rpb24oeCkgeC9zdW0oeCkpKQplbmRfZGYkRnJlcW5vcm1faCA9IGVuZF9kZiRGcmVxbm9ybS9tZWFuKGVuZF9kZiRGcmVxbm9ybVtlbmRfZGYkVmFyMT09ImhlYWx0aHkiXSkKCnBsdF9kaXN0cyA9IGdncGxvdChlbmRfZGYsIGFlcyh4ID0gVmFyMiwgZmlsbCA9IFZhcjEsIHkgPSBGcmVxbm9ybV9oKSkrCiAgICAgZmFjZXRfd3JhcCh+VmFyMSkrCiAgICAgZ2VvbV9jb2woKSsKICAgICBsYWJzKHggPSAiem9uYXRpb24gKGJpbm5lZCkiLCB5ID0gIlByb3BvcnRpb24gb2YgY2VsbHMgKGNvbXBhcmVkIHRvIGhlYWx0aHkpIikrCiAgICAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwwKSwgbGFiZWxzID0gYygiMCIsICIwLjUiLCAiMSIsICIxLjUiLCAiMiIpKSsKICAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjb2xjb25kKSsKICAgICBjb29yZF9mbGlwKCkrCiAgICAgZ3VpZGVzKGZpbGwgPSBndWlkZV9sZWdlbmQodGl0bGUucG9zaXRpb24gPSAibGVmdCIpKSsKICAgICB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gNiksCiAgICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQoKcGRmKCJmaWd1cmVfcGFuZWxzL2ZpZ19lbmRvL2VuZG9fem9uYXRpb25fY29uZGl0aW9uRGlzdF9ub3JtLnBkZiIsIAogICAgaGVpZ2h0ID0gMiwgd2lkdGggPSAzLjgsIHVzZURpbmdiYXRzID0gRikKcHJpbnQocGx0X2Rpc3RzKQpkZXYub2ZmKCkKYGBgCgpEb25vciBkaXN0cmlidXRpb25zCgpgYGB7cn0KZW5kX2RmID0gb25seV9lbmRfY2VsbHNAbWV0YS5kYXRhW29ubHlfZW5kX2NlbGxzJGdvb2RjbCxdCgplbmRfZGYgPSBkYXRhLmZyYW1lKHZhbHMgPSBlbmRfZGYkem9uYXRpb25fcHQsIAogICAgICAgICAgICAgICAgICAgIENvbmRpdGlvbiA9IGVuZF9kZiRDb25kaXRpb24sCiAgICAgICAgICAgICAgICAgICAgRG9ub3IgPSBlbmRfZGYkRG9ub3IsCiAgICAgICAgICAgICAgICAgICAgY3QgPSBlbmRfZGYkZW5kb19zaW1wKQplbmRfZGYkYmluczEwID0gY3V0KGVuZF9kZiR2YWxzLCAxMCkKZW5kX2RmJENvbmRpdGlvbiA9IGZhY3RvcihlbmRfZGYkQ29uZGl0aW9uLCBsZXZlbHMgPSBjKCJoZWFsdGh5IiwgInJlZ2VuZXJhdGluZyIsICJlbWJvbGlzZWQiKSkKZW5kX2RmJERvbm9yID0gZmFjdG9yKGVuZF9kZiREb25vcikKZW5kX2RmJERvbm9yID0gcGx5cjo6cmV2YWx1ZShlbmRfZGYkRG9ub3IsIGMoIkhEMSIgPSAic2NfSDEiLCAiSEQyIiA9ICJzY19IMiIsICJIRDMiID0gInNjX0gzIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJERDEiID0gInNjX1IxL0UxIiwgIkREMiIgPSAic2NfUjIvRTIiLCAiREQzIiA9ICJzY19SMy9FMyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJERDUiID0gInNjX1I0L0U0IiwgIkRENiIgPSAic2NfUjUvRTUiLCAiREQ3IiA9ICJzY19SNi9FNiIpKQplbmRfZGYkRG9ub3IgPSBmYWN0b3IoZW5kX2RmJERvbm9yLCBsZXZlbHMgPSBsZXZlbHMoZW5kX2RmJERvbm9yKVtjKDc6OSwgMTo2KV0pCgplbmRfZG9uID0gZ2dwbG90KGVuZF9kZiwgYWVzKHggPSB2YWxzLCBjb2xvdXIgPSBDb25kaXRpb24pKSsKICBmYWNldF93cmFwKH5Eb25vciwgc2NhbGVzID0gImZyZWVfeSIpKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDApKwogIGdlb21fZGVuc2l0eShzaXplID0gMS4wNSkrCiAgbGFicyh4ID0gIlpvbmF0aW9uIiwgeSA9ICJDZWxsIGRlbnNpdHkiKSsKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGNvbGNvbmQpKwogIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBjKDAsMCkpKwogIGNvb3JkX2ZsaXAoKSsKICBndWlkZXMoY29sb3VyID0gZ3VpZGVfbGVnZW5kKHRpdGxlLnBvc2l0aW9uID0gImxlZnQiLCBuY29sID0gMykpKwogIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MueCA9IGVsZW1lbnRfbGluZSgpLAogICAgICAgIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQobWFyZ2luID0gbWFyZ2luKDAuMDQsMCwwLjA0LDAsICJjbSIpLCBzaXplID0gNy41KSwKICAgICAgICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAid2hpdGUiLCBjb2xvdXIgPSAid2hpdGUiKSwKICAgICAgICBsZWdlbmQudGl0bGUuYWxpZ24gPSAwLAogICAgICAgIGFzcGVjdC5yYXRpbyA9IDAuOCwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwKICAgICAgICBsZWdlbmQuYm94Lm1hcmdpbiA9IG1hcmdpbigwLDAsMCwwKSwKICAgICAgICBsZWdlbmQuYm94LnNwYWNpbmcgPSB1bml0KDAuMDUsICJjbSIpKQoKcGRmKCJmaWd1cmVfcGFuZWxzL2ZpZ19lbmRvL2VuZF96b25hdGlvbl9Eb25vcnNDb25kLnBkZiIsIGhlaWdodCA9IDMuOCwgd2lkdGggPSAzLjQsIHVzZURpbmdiYXRzID0gRikKcHJpbnQoZW5kX2RvbikKZGV2Lm9mZigpCmBgYAoKUHJlZGljdGVkIHpvbmF0aW9uIGZvciBvdGhlciBwb3B1bGF0aW9ucwoKYGBge3IsIGZpZy53aWR0aD0zLjg1LCBmaWcuaGVpZ2h0PTMuNX0KcGxvdF9kZiA9IG9ubHlfZW5kX2NlbGxzQG1ldGEuZGF0YVtvbmx5X2VuZF9jZWxsc0BtZXRhLmRhdGEkZW5kb19zaW1wICVpbiUgbmFtZXMoZW5kb19jb2wpWzE6OV0sXQpwbG90X2RmJGJpbnMxMDAgPSBjdXQocGxvdF9kZiR6b25hdGlvbl9wdCwgMTApCnBsb3RfZGYkQ29uZGl0aW9uID0gZmFjdG9yKHBsb3RfZGYkQ29uZGl0aW9uLCBsZXZlbHMgPSBjKCJoZWFsdGh5IiwgImVtYm9saXNlZCIsICJyZWdlbmVyYXRpbmciKSkKcGxvdF9kZiRlbmRvX3NpbXAgPSBmYWN0b3IocGxvdF9kZiRlbmRvX3NpbXAsIGxldmVscyA9IG5hbWVzKGVuZG9fY29sKSkKCnBsb3RfcHRhbGwgPSBnZ3Bsb3QocGxvdF9kZiwgYWVzKHkgPSB6b25hdGlvbl9wdCwgeCA9IGVuZG9fc2ltcCwgZmlsbCA9IENvbmRpdGlvbikpKwogIGZhY2V0X3dyYXAofmVuZG9fc2ltcCwgc2NhbGVzID0gImZyZWVfeCIsIG5jb2wgPSAzKSsKICBnZW9tX3Zpb2xpbigpKwogIGxhYnMoeSA9ICJ6b25hdGlvbiIsIHggPSAiY2x1c3RlcnMiKSsKICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLDApLCBicmVha3MgPSBjKDAsIDAuMjUsIDAuNSwgMC43NSwgMSksIGxpbWl0cyA9IGMoMCwxKSkrCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY29sY29uZCkrCiAgZ3VpZGVzKGZpbGwgPSBndWlkZV9sZWdlbmQodGl0bGUucG9zaXRpb24gPSAibGVmdCIpKSsKICB0aGVtZV9idygpKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChjb2xvdXIgPSAiYmxhY2siLCBzaXplID0gNyksCiAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gOCksCiAgICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIndoaXRlIiwgY29sb3VyID0gImJsYWNrIiksCiAgICAgICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gOCksCiAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGxlZ2VuZC5rZXkuc2l6ZSA9IHVuaXQoMC4zLCAiY20iKSwKICAgICAgICBsZWdlbmQuYm94LnNwYWNpbmcgPSB1bml0KDAuMDEsICJjbSIpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKQoKcGRmKCJmaWd1cmVfcGFuZWxzL2ZpZ19lbmRvL3pvbmF0aW9uX2FsbExTRUMucGRmIiwgaGVpZ2h0PTMuNSwgd2lkdGg9My44NSwgdXNlRGluZ2JhdHMgPSBGKQpwcmludChwbG90X3B0YWxsKQpkZXYub2ZmKCkKYGBgCgpIZWF0bWFwCgpgYGB7cn0Kb25seV9lbmRfY2VsbHNfc3BsaXQgPSBTcGxpdE9iamVjdChvbmx5X2VuZF9jZWxsc1ssb25seV9lbmRfY2VsbHMkZ29vZGNsXSwgc3BsaXQuYnkgPSAiQ29uZGl0aW9uIikKCiMgZmlsdGVyIG1hcmtlcnMgZnJvbSBvdGhlciBjZWxsIHR5cGVzIChjYW4gY29udGFtaW5hdGUpCm1rX290aGVycyA9IHVuaXF1ZSh1bmxpc3QodG9wX2dlbmVzJGNlbGxfdHlwZVshZ3JlcGwoIkxTRUMgIiwgbmFtZXModG9wX2dlbmVzJGNlbGxfdHlwZSkpXSkpCmNvcl9zdWIgPSBhbGxfY29yX2VuZFshKGFsbF9jb3JfZW5kJGdlbmUgJWluJSBta19vdGhlcnMpLF0KCnRvcGdlbmVzID0gdW5pcXVlKGMoY29yX3N1YiRnZW5lW29yZGVyKGNvcl9zdWIkSHZFLCBkZWNyZWFzaW5nID0gVCldWzE6MzBdLAogICAgICAgICAgICAgICAgICAgIGNvcl9zdWIkZ2VuZVtvcmRlcihjb3Jfc3ViJEh2UiwgZGVjcmVhc2luZyA9IFQpXVsxOjMwXSkpCmJvdHRvbWdlbmVzID0gdW5pcXVlKGMoY29yX3N1YiRnZW5lW29yZGVyKGNvcl9zdWIkSHZFLCBkZWNyZWFzaW5nID0gRildWzE6MzVdLAogICAgICAgICAgICAgICAgICAgIGNvcl9zdWIkZ2VuZVtvcmRlcihjb3Jfc3ViJEh2UiwgZGVjcmVhc2luZyA9IEYpXVsxOjM1XSkpCgp1c2VnZW5lcyA9IGModG9wZ2VuZXMsIGJvdHRvbWdlbmVzKQoKYmluc19saXN0ID0gbGlzdCgpCmZvcihuIGluIG5hbWVzKG9ubHlfZW5kX2NlbGxzX3NwbGl0KSl7CiAgcGxvdF9kZiA9IGNiaW5kKGRhdGEuZnJhbWUoInB0IiA9IHJlcCgxOjEwLCBlYWNoID0gMTApKSxlbmRfZml0c19xdmFsW1tuXV0kZml0c1ssdXNlZ2VuZXNdKQogIHBsb3RfZGYkYmluczEwID0gY3V0KHBsb3RfZGYkcHQsIDEwKQogIGJpbnNfbGlzdFtbbl1dID0gc2FwcGx5KHVzZWdlbmVzLCBmdW5jdGlvbih4KSBzY2FsZSh0YXBwbHkocGxvdF9kZlsseF0sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGxvdF9kZiRiaW5zMTAsIG1lYW4pKVsxMDoxXSkKfQpiaW5zX21lYW4gPSBSZWR1Y2UocmJpbmQsIGJpbnNfbGlzdCkKCmhjdCA9IGhjbHVzdChkaXN0KHQoYmluc19saXN0JGhlYWx0aHlbLHRvcGdlbmVzXSkpLCBtZXRob2QgPSAid2FyZC5EMiIpCmhjYiA9IGhjbHVzdChkaXN0KHQoYmluc19tZWFuWyxib3R0b21nZW5lc10pKSwgbWV0aG9kID0gIndhcmQuRDIiKQpvcmQgPSBjKHRvcGdlbmVzW2hjdCRvcmRlcl0sIGJvdHRvbWdlbmVzW2hjYiRvcmRlcl0pCmN1dGIgPSBmYWN0b3IoY3V0cmVlKGhjYiwgMTApW2hjYiRvcmRlcl0sIGxldmVscyA9IHVuaXF1ZShjdXRyZWUoaGNiLCA4KVtoY2Ikb3JkZXJdKSkKCmdhcHMgPSBjdW1zdW0odGFibGUoY3V0YikpWy0xMF0rbGVuZ3RoKHRvcGdlbmVzKQoKaGVhdF9wbHQgPSBwaGVhdG1hcChiaW5zX21lYW5bLG9yZF0sIHNob3dfcm93bmFtZXMgPSBGLCBmb250c2l6ZV9jb2wgPSA2LjIsIGJvcmRlcl9jb2xvciA9IE5BLAogICAgICAgICAgICAgICAgICAgIGdhcHNfcm93ID0gYygxMCwyMCksIGdhcHNfY29sID0gYyhsZW5ndGgodG9wZ2VuZXMpLCBnYXBzKSwKICAgICAgICAgICAgICAgICAgICBjbHVzdGVyaW5nX21ldGhvZCA9ICJ3YXJkLkQyIiwgY2x1c3Rlcl9yb3dzID0gRiwgY2x1c3Rlcl9jb2xzID0gRikKCnBkZigiZmlndXJlX3BhbmVscy9maWdfZW5kby9oZWF0bWFwX2Nvclpvbi5wZGYiLCBoZWlnaHQ9Mywgd2lkdGg9Ny44LCB1c2VEaW5nYmF0cyA9IEYpCnByaW50KGhlYXRfcGx0KQpkZXYub2ZmKCkKYGBgCgpHTyBUZXJtcwoKYGBge3J9CmdvX3RoZW1lID0gdGhlbWVfYncoKSsKICB0aGVtZShheGlzLnRleHQgPSBlbGVtZW50X3RleHQoY29sb3VyID0gImJsYWNrIiwgc2l6ZSA9IDcuNSksCiAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gOCksCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gOSksCiAgICAgICAgcGxvdC50aXRsZS5wb3NpdGlvbiA9ICJwbG90IiwKICAgICAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA3LjUpLAogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHZqdXN0ID0gMC42LCBjb2xvdXIgPSBjKCJncmV5NDUiLCAiZ3JleTE3IikpLAogICAgICAgIHBhbmVsLmdyaWQubWFqb3IueSA9IGVsZW1lbnRfYmxhbmsoKSkKCmdvcGx0RnVuYyA9IGZ1bmN0aW9uKHBsb3RfZGYsIHRpdCA9ICIiLCBzdWJ0aXQgPSAiIil7CiAgcGxvdF9kZiREZXNjcmlwdGlvbiA9IGJyZWFrU3RyKHBsb3RfZGYkRGVzY3JpcHRpb24sIDMwKQogIHBsb3RfZGYkRGVzY3JpcHRpb24gPSBmYWN0b3IocGxvdF9kZiREZXNjcmlwdGlvbiwgbGV2ZWxzID0gcmV2KHBsb3RfZGYkRGVzY3JpcHRpb24pKQogIHBsb3RfZGYkZmlsbCA9IGFzLmNoYXJhY3RlcihyZXAoMToyLCBjZWlsaW5nKG5yb3cocGxvdF9kZikvMikpKVsxOm5yb3cocGxvdF9kZildCiAgcGx0ID0gZ2dwbG90KHBsb3RfZGYsIGFlcyh4ID0gLWxvZzEwKHF2YWx1ZSksIHkgPSBEZXNjcmlwdGlvbiwgZmlsbCA9IGZpbGwpKSsKICAgIGdlb21fY29sKHNob3cubGVnZW5kID0gRikrCiAgICBzY2FsZV94X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLDApLCBsaW0gPSBjKDAsIG1heCgtbG9nMTAocGxvdF9kZiRxdmFsdWUpKSsxKSkrCiAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJncmV5MTciLCAiZ3JleTQ1IikpKwogICAgbGFicyh0aXRsZSA9IHRpdCwgc3VidGl0bGUgPSBzdWJ0aXQpKwogICAgZ29fdGhlbWUKICByZXR1cm4ocGx0KQp9CgpwZGYoImZpZ3VyZV9wYW5lbHMvZmlnX2VuZG8vZW5kX2dvX2VtYl9jb3JyLnBkZiIsIGhlaWdodCA9IDMuMiwgd2lkdGggPSAzLjYsIHVzZURpbmdiYXRzID0gRikKcHJpbnQoZ29wbHRGdW5jKGdvX2VuZCRjb3JfaGUsIHRpdCA9ICJHTyBUZXJtcyAtIEVtYm9saXNlZCIsIHN1YnRpdCA9ICJjb3IgPj0gMC4zIikpCmRldi5vZmYoKQoKcGRmKCJmaWd1cmVfcGFuZWxzL2ZpZ19lbmRvL2VuZF9nb19yZWdfY29yci5wZGYiLCBoZWlnaHQgPSAzLjIsIHdpZHRoID0gMy42LCB1c2VEaW5nYmF0cyA9IEYpCnByaW50KGdvcGx0RnVuYyhnb19lbmQkY29yX2hyLCB0aXQgPSAiR08gVGVybXMgLSBSZWdlbmVyYXRpbmciLCBzdWJ0aXQgPSAiY29yID49IDAuMyIpKQpkZXYub2ZmKCkKYGBgCgoKCiMgRmlndXJlIDUKIyMgTWFpbiBGaWd1cmUKVG90YWwgaW50ZXJhY3Rpb25zIHBlciBjZWxsIHR5cGUgaW4gZWFjaCBjb25kaXRpb24KCmBgYHtyfQpuZXRfbmFtZXNfbCA9IHJlYWRSRFMoZmlsZSA9ICJyZXN1bHRzL2NlbGxfY29tbS91cGR0L2NvdW50X25ldF9saXN0LlJEUyIpCiMgbGlzdCBwZXIgY29uZGl0aW9uIHdpdGggaW50ZXJhY3Rpb25zLCBnZW5lcywgbWVhbgpyZWZvcm1fbGlzdCA9IHJlYWRSRFMoZmlsZSA9ICJyZXN1bHRzL2NlbGxfY29tbS91cGR0L3JlZm9ybV9saXN0LlJEUyIpCiMgbGlzdCBwZXIgY29uZCB3aXRoIGxpZ2FuZCBvciByZWNlcHRvciBleHByZXNzaW9uIGZvciBlYWNoIGludGVyYWN0aW9uCnNjb3JpbmdfbWF0cyA9IHJlYWRSRFMoZmlsZSA9ICJyZXN1bHRzL2NlbGxfY29tbS91cGR0L3Njb3JpbmdfbWF0cy5SRFMiKQojIHJlZm9ybV9saXN0ICsgREUgaW5mbyArIHVuaXF1ZW5lc3Mvc3BlY2lmaWNpdHkgb2YgaW50ZXJhY3Rpb24vbGlnYW5kL3JlY2VwdG9yCmludGVyX2RmID0gcmVhZFJEUyhmaWxlID0gInJlc3VsdHMvY2VsbF9jb21tL3VwZHQvY29uZF9kaWZmX2ludGVyYWN0X0RFLlJEUyIpCiMgaW50ZXJhY3Rpb25zIHFpdGggY2VydGFpbiBmdW5jdGlvbnMgaW52b2x2aW5nIHdoaWNoIGNlbGwgdHlwZXMgYW5kIGluIHdoaWNoIGNvbmRpdGlvbnMKY3RfZ19jb25kX2FubiA9IHJlYWRSRFMoZmlsZSA9ICJyZXN1bHRzL2NlbGxfY29tbS91cGR0L2N0X2dfY29uZF9hbm4uUkRTIikKIyBpbnRlcmFjdGlvbiB3aXRoIEwgYW5kIFIsIHBhaXIgb2YgY2VsbCB0eXBlcywgbWVhbiBleHAsIGFuZCBmdW5jdGlvbgpjdF9pbnRfZXhwX2wgPSByZWFkUkRTKGZpbGUgPSAicmVzdWx0cy9jZWxsX2NvbW0vdXBkdC9pbnRlcmFjdF9jZWxsdHlwZV9leHBfZ3JvdXBfbGlzdC5SRFMiKQojIGFubm90YXRpb24gZm9yIGFsbCBpbnRlcmFjdGlvbnMKaW50ZXJfYW5ub3QgPSByZWFkLmNzdigiZGF0YS9pbnRlcmFjdGlvbl9hbm5vdGF0aW9uLmNzdiIsIGhlYWRlciA9IFQpCmludGVyX2Fubm90JGZ1bmN0W2dyZXBsKCJpbW0iLCBpbnRlcl9hbm5vdCRmdW5jdCldID0gImltbXVuZSIKaW50ZXJfYW5ub3QkZnVuY3RbZ3JlcGwoImluZmxhbSIsIGludGVyX2Fubm90JGZ1bmN0KV0gPSAiaW1tdW5lIgojIG11dCBpbmZvIGRhdGEKaGVyX2FsbGludCA9IHJlYWRSRFMoZmlsZSA9ICIuL3Jlc3VsdHMvY2VsbF9jb21tL3VwZHQvaW50ZXJhY3Rpb25zX211dEluZm9fY29uZENvbXAuUkRTIikKIyBHU0VBIG9uIG11dHVhbCBpbmZvIHJlc3VsdHMKYWxsX2dzZWFfbGlzdCA9IHJlYWRSRFMoZmlsZSA9ICIuL3Jlc3VsdHMvY2VsbF9jb21tL3VwZHQvYWxsZ3NlYV9pbnRlcmFjdGlvbnNfbXV0SW5mb19jb25kQ29tcC5SRFMiKQpzaW1wX2dzZWFfbGlzdCA9IHJlYWRSRFMoZmlsZSA9ICIuL3Jlc3VsdHMvY2VsbF9jb21tL3VwZHQvc2ltcGdzZWFfaW50ZXJhY3Rpb25zX211dEluZm9fY29uZENvbXAuUkRTIikKIyBuZXR3b3JrIGRhdGEKbG9hZCgicmVzdWx0cy9jZWxsX2NvbW0vdXBkdC9tZWRpYW5fbmV0d29ya3NfY29uZC5SRGF0YSIpCmxvYWQoInJlc3VsdHMvY2VsbF9jb21tL3VwZHQvbmV0d29ya3NfY29uZC5SRGF0YSIpCmxvYWQoInJlc3VsdHMvY2VsbF9jb21tL3VwZHQvbWVkaWFuX25ldHdvcmtzX2NvbmRfbWlkY3QuUkRhdGEiKQpsb2FkKCJyZXN1bHRzL2NlbGxfY29tbS91cGR0L21lZGlhbl9uZXR3b3Jrc19jb25kX3VtYXAuUkRhdGEiKQpsb2FkKCJyZXN1bHRzL2NlbGxfY29tbS91cGR0L25ldHdvcmtzX2NvbmRfdW1hcC5SRGF0YSIpCmxvYWQoInJlc3VsdHMvY2VsbF9jb21tL3VwZHQvbWVkaWFuX25ldHdvcmtzX2NvbmRfdW1hcF9taWRjdC5SRGF0YSIpCmNvbXBoX2ludGVycyA9IHJlYWRSRFMoZmlsZSA9ICJyZXN1bHRzL2NlbGxfY29tbS91cGR0L2NvbXBoX2ludGVycy5SRFMiKQpgYGAKClBsb3QgY2hhbmdlcyBpbiBudW1iZXIgb2YgaW50ZXJhY3Rpb25zIHBlciBjb25kaXRpb24KCmBgYHtyfQojIGNvcnJlY3Qgc29tZSBuYW1lcwpyZWZvcm1fbGlzdF9pbnQgPSBsaXN0KCkKZm9yKG4gaW4gbmFtZXMocmVmb3JtX2xpc3QpWzE6M10pewogIHJlZm9ybV9saXN0W1tuXV0kY3QxW2dyZXBsKCJIZXBhIiwgcmVmb3JtX2xpc3RbW25dXSRjdDEpXSA9ICJIZXBhdG9jeXRlcyIKICByZWZvcm1fbGlzdFtbbl1dJGN0MltncmVwbCgiSGVwYSIsIHJlZm9ybV9saXN0W1tuXV0kY3QyKV0gPSAiSGVwYXRvY3l0ZXMiCiAgcmVmb3JtX2xpc3RbW25dXSRjdDFbZ3JlcGwoIkxTRUNfIiwgcmVmb3JtX2xpc3RbW25dXSRjdDEpXSA9ICJMU0VDIgogIHJlZm9ybV9saXN0W1tuXV0kY3QyW2dyZXBsKCJMU0VDXyIsIHJlZm9ybV9saXN0W1tuXV0kY3QyKV0gPSAiTFNFQyIKICByZWZvcm1fbGlzdF9pbnRbW25dXSA9IHJlZm9ybV9saXN0W1tuXV1bcmVmb3JtX2xpc3RbW25dXSRjdDEhPSJEaXZpZGluZyBjZWxscyIgJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlZm9ybV9saXN0W1tuXV0kY3QyIT0iRGl2aWRpbmcgY2VsbHMiLF0KICByZWZvcm1fbGlzdF9pbnRbW25dXSA9IHJlZm9ybV9saXN0X2ludFtbbl1dWyFkdXBsaWNhdGVkKHJlZm9ybV9saXN0X2ludFtbbl1dWywxOjNdKSwxOjNdCn0KCiMgY291bnQgaW50ZXJhY3Rpb25zCmluZmVyX2RmID0gZGF0YS5mcmFtZShleHBhbmQuZ3JpZCh1bmlxdWUocmVmb3JtX2xpc3RfaW50JGhlYWx0aHkkY3QxKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1bmlxdWUocmVmb3JtX2xpc3RfaW50JGhlYWx0aHkkY3QxKSkpCm5yID0gbnJvdyhpbmZlcl9kZikKaW5mZXJfZGYgPSByYmluZChpbmZlcl9kZiwgaW5mZXJfZGYsIGluZmVyX2RmKQppbmZlcl9kZiRjb3VudCA9IDAKaW5mZXJfZGYkY29uZCA9IHJlcChuYW1lcyhyZWZvcm1fbGlzdClbMTozXSwgZWFjaCA9IG5yKQpjb2xuYW1lcyhpbmZlcl9kZilbMToyXSA9IGMoIlNPVVJDRSIsICJUQVJHRVQiKQpmb3IoaSBpbiAxOm5yb3coaW5mZXJfZGYpKXsKICB0bXAgPSByZWZvcm1fbGlzdF9pbnRbW2luZmVyX2RmW2ksNF1dXQogIGluZmVyX2RmW2ksM10gPSBkaW0odG1wWyh0bXAkY3QxPT1pbmZlcl9kZltpLDFdICYgdG1wJGN0Mj09aW5mZXJfZGZbaSwyXSkgfAogICAgICAgICAgICAgICAgICAgICAgICAgICAgKHRtcCRjdDI9PWluZmVyX2RmW2ksMV0gJiB0bXAkY3QxPT1pbmZlcl9kZltpLDJdKSxdKVsxXQp9CiMjIG1ha2Ugb25lIHRvIGNvdW50IG92ZXIgYWxsCmluZmVyX2FsbCA9IGRhdGEuZnJhbWUoZXhwYW5kLmdyaWQodW5pcXVlKHJlZm9ybV9saXN0X2ludCRoZWFsdGh5JGN0MSksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVuaXF1ZShyZWZvcm1fbGlzdF9pbnQkaGVhbHRoeSRjdDEpKSkKaW5mZXJfYWxsJGNvdW50ID0gMApjb2xuYW1lcyhpbmZlcl9hbGwpWzE6Ml0gPSBjKCJTT1VSQ0UiLCAiVEFSR0VUIikKcmVmb3JtX2FsbF9pbnQgPSB1bmlxdWUoUmVkdWNlKHJiaW5kLCByZWZvcm1fbGlzdF9pbnQpKQpmb3IoaSBpbiAxOm5yb3coaW5mZXJfYWxsKSl7CiAgaW5mZXJfYWxsW2ksM10gPSBpbmZlcl9hbGxbaSwzXStkaW0odG1wWyhyZWZvcm1fYWxsX2ludCRjdDE9PWluZmVyX2FsbFtpLDFdICYgcmVmb3JtX2FsbF9pbnQkY3QyPT1pbmZlcl9hbGxbaSwyXSkgfAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChyZWZvcm1fYWxsX2ludCRjdDI9PWluZmVyX2FsbFtpLDFdICYgcmVmb3JtX2FsbF9pbnQkY3QxPT1pbmZlcl9hbGxbaSwyXSksXSlbMV0KfQoKaW5mZXJfZGZfbGlzdCA9IGxpc3QoaGVhbHRoeSA9IGluZmVyX2RmW2luZmVyX2RmJGNvbmQ9PSJoZWFsdGh5IixdLAogICAgICAgICAgICAgICAgICAgICBlbWJvbGlzZWQgPSBpbmZlcl9kZltpbmZlcl9kZiRjb25kPT0iZW1ib2xpc2VkIixdLAogICAgICAgICAgICAgICAgICAgICByZWdlbmVyYXRpbmcgPSBpbmZlcl9kZltpbmZlcl9kZiRjb25kPT0icmVnZW5lcmF0aW5nIixdLAogICAgICAgICAgICAgICAgICAgICBhbGwgPSBpbmZlcl9hbGwpCgpuZXRfbmFtZXNfYWxsID0gdChSZWR1Y2UocmJpbmQsIGxhcHBseShpbmZlcl9kZl9saXN0WzE6M10sIGZ1bmN0aW9uKHgpIHRhcHBseSh4JGNvdW50LCB4JFNPVVJDRSwgc3VtKSkpKQpjb2xuYW1lcyhuZXRfbmFtZXNfYWxsKSA9IG5hbWVzKG5ldF9uYW1lc19sKVsxOjNdCm5ldF9uYW1lc19hbGwgPSByZXNoYXBlMjo6bWVsdChuZXRfbmFtZXNfYWxsKQpuZXRfbmFtZXNfYWxsJFZhcjEgPSBmYWN0b3IobmV0X25hbWVzX2FsbCRWYXIxLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IG5ldF9uYW1lc19hbGxbbmV0X25hbWVzX2FsbCRWYXIyPT0iaGVhbHRoeSIsIlZhcjEiXVtvcmRlcihuZXRfbmFtZXNfYWxsW25ldF9uYW1lc19hbGwkVmFyMj09ImhlYWx0aHkiLCJ2YWx1ZSJdLCBkZWNyZWFzaW5nID0gRildKQoKdG90YWxfdW5pcXVlID0gZGF0YS5mcmFtZSh0KHQoUmVkdWNlKHJiaW5kLCBsYXBwbHkoaW5mZXJfZGZfbGlzdFs0XSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uKHgpIHRhcHBseSh4JGNvdW50LCB4JFNPVVJDRSwgc3VtKSkpKSkpCnRvdGFsX3VuaXF1ZSRWYXIxID0gcm93bmFtZXModG90YWxfdW5pcXVlKQpjb2xuYW1lcyh0b3RhbF91bmlxdWUpWzFdID0gInZhbHVlIgp0b3RhbF91bmlxdWUkVmFyMiA9ICJ0b3RhbCB1bmlxdWUiCgpuZXRfbmFtZXNfYWxsJFZhcjEgPSBmYWN0b3IobmV0X25hbWVzX2FsbCRWYXIxLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IHRvdGFsX3VuaXF1ZSRWYXIxW29yZGVyKHRvdGFsX3VuaXF1ZSR2YWx1ZSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZWNyZWFzaW5nID0gRildKQpwbHRfY291bnRzID0gZ2dwbG90KG5ldF9uYW1lc19hbGwsIGFlcyh4ID0gVmFyMSwgeSA9IHZhbHVlKSkrCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKGNvbG91ciA9IFZhcjIpLCBzaXplID0gMS42KSsKICBnZW9tX3BvaW50KGRhdGEgPSB0b3RhbF91bmlxdWUsIG1hcHBpbmcgPSBhZXMoc2hhcGUgPSBWYXIyKSwgc2l6ZSA9IDEuNikrCiAgY29vcmRfZmxpcCgpKwogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gY29sY29uZCkrCiAgc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcyA9IGMoNCkpKwogIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBjKDAsMCksIGxpbWl0cyA9IGMoMCw2NTAwKSkrCiAgbGFicyh5ID0gIlRvdGFsIGludGVyYWN0aW9ucyIsIHggPSAiQ2VsbCBUeXBlIiwgY29sb3VyID0gIkNvbmRpdGlvbiIpKwogIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9sZWdlbmQob3JkZXIgPSAxKSwgc2hhcGUgPSBndWlkZV9sZWdlbmQob3JkZXIgPSAyLCB0aXRsZSA9IE5VTEwpKSsKICB0aGVtZV9idygpKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMzAsIHZqdXN0ID0gMSwgaGp1c3QgPSAxKSwKICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoY29sb3VyID0gImJsYWNrIiksCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemUgPSA4KSwKICAgICAgICBsZWdlbmQubWFyZ2luID0gbWFyZ2luKDEsIDEsIDEsIDEpLAogICAgICAgIGxlZ2VuZC5zcGFjaW5nLnggPSB1bml0KDAuMDUsICJjbSIpLAogICAgICAgIGxlZ2VuZC5kaXJlY3Rpb24gPSAiaG9yaXpvbnRhbCIsbGVnZW5kLmJveCA9ICJob3Jpem9udGFsIikKbGVnID0gY293cGxvdDo6Z2V0X2xlZ2VuZChwbHRfY291bnRzKQoKcGVyY19kZiA9IGRhdGEuZnJhbWUoIlZhcjEiID0gbmV0X25hbWVzX2FsbCRWYXIxLAogICAgICAgICAgICAgICAgICAgICAiVmFyMiIgPSBuZXRfbmFtZXNfYWxsJFZhcjIsCiAgICAgICAgICAgICAgICAgICAgICJwZXJjIiA9IGMocmVwKDAsIGxlbmd0aCh1bmlxdWUobmV0X25hbWVzX2FsbCRWYXIxKSkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChuZXRfbmFtZXNfYWxsJHZhbHVlW25ldF9uYW1lc19hbGwkVmFyMj09ImVtYm9saXNlZCJdLW5ldF9uYW1lc19hbGwkdmFsdWVbbmV0X25hbWVzX2FsbCRWYXIyPT0iaGVhbHRoeSJdKS9uZXRfbmFtZXNfYWxsJHZhbHVlW25ldF9uYW1lc19hbGwkVmFyMj09ImhlYWx0aHkiXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAobmV0X25hbWVzX2FsbCR2YWx1ZVtuZXRfbmFtZXNfYWxsJFZhcjI9PSJyZWdlbmVyYXRpbmciXS1uZXRfbmFtZXNfYWxsJHZhbHVlW25ldF9uYW1lc19hbGwkVmFyMj09ImhlYWx0aHkiXSkvbmV0X25hbWVzX2FsbCR2YWx1ZVtuZXRfbmFtZXNfYWxsJFZhcjI9PSJoZWFsdGh5Il0pKjEwMCkKcGVyY19kZiRjb2wgPSBpZmVsc2UocGVyY19kZiRwZXJjPjAsICJncmVlbiIsICJyZWQiKQpwZXJjX2RmID0gcGVyY19kZltwZXJjX2RmJFZhcjIhPSJoZWFsdGh5IixdCgpwZXJjX3BsdF9lbWIgPSBnZ3Bsb3QocGVyY19kZltwZXJjX2RmJFZhcjI9PSJlbWJvbGlzZWQiLF0sIGFlcyh4ID0gVmFyMSwgeSA9IHBlcmMsIGZpbGwgPSBjb2wpKSsKICBnZW9tX2NvbCgpKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoImRlZXBza3libHVlMSIsICJyZWQxIikpKwogIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBjKDAsMCksIGxpbWl0cyA9IGMoLTQ1LDcwKSkrCiAgY29vcmRfZmxpcCgpKwogIGxhYnMoeSA9ICIlIGNoYW5nZVxuZW1ib2xpc2VkIHZzIGhlYWx0aHkiLCB4ID0gIkNlbGwgVHlwZSIpKwogIHRoZW1lX2J3KCkrCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSAzMCwgdmp1c3QgPSAxLCBoanVzdCA9IDEsIGNvbG91ciA9ICJibGFjayIpLAogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplID0gOCksCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCnBlcmNfcGx0X3JlZyA9IGdncGxvdChwZXJjX2RmW3BlcmNfZGYkVmFyMj09InJlZ2VuZXJhdGluZyIsXSwgYWVzKHggPSBWYXIxLCB5ID0gcGVyYywgZmlsbCA9IGNvbCkpKwogIGdlb21fY29sKCkrCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiZGVlcHNreWJsdWUxIiwgInJlZDEiKSkrCiAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwwKSwgbGltaXRzID0gYygtNDUsNzApKSsKICBjb29yZF9mbGlwKCkrCiAgbGFicyh5ID0gIiUgY2hhbmdlXG5yZWdlbmVyYXRpbmcgdnMgaGVhbHRoeSIsIHggPSAiQ2VsbCBUeXBlIikrCiAgdGhlbWVfYncoKSsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDMwLCB2anVzdCA9IDEsIGhqdXN0ID0gMSwgY29sb3VyID0gImJsYWNrIiksCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemUgPSA4KSwKICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aWNrcy55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKCmNvd3Bsb3Q6OnBsb3RfZ3JpZChjb3dwbG90OjpwbG90X2dyaWQocGx0X2NvdW50cyt0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwZXJjX3BsdF9lbWIsIHBlcmNfcGx0X3JlZywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmNvbCA9IDMsIGFsaWduID0gImgiLCBheGlzID0gInIiLCByZWxfd2lkdGhzID0gYygxLDAuNSwwLjUpKSwKICAgICAgICAgICAgICAgICAgIGxlZywgbnJvdyA9IDIsIHJlbF9oZWlnaHRzID0gYygxLCAwLjEpKQoKcGRmKCJmaWd1cmVfcGFuZWxzX3JldjEvZmlnX2NvbW0vbWFpbkZpZ19jb3VudHNDb25kLnBkZiIsIGhlaWdodCA9IDcsIHdpZHRoID0gNykKY293cGxvdDo6cGxvdF9ncmlkKGNvd3Bsb3Q6OnBsb3RfZ3JpZChwbHRfY291bnRzK3RoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBlcmNfcGx0X3JlZywgcGVyY19wbHRfZW1iLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuY29sID0gMywgYWxpZ24gPSAiaCIsIGF4aXMgPSAiciIsIHJlbF93aWR0aHMgPSBjKDEsMC40LDAuNCkpLAogICAgICAgICAgICAgICAgICAgbGVnLCBucm93ID0gMiwgcmVsX2hlaWdodHMgPSBjKDEsIDAuMSkpCmRldi5vZmYoKQpgYGAKCk5vbi11YmlxdWl0b3VzIGludGVyYWN0aW9uIGZ1bmN0aW9ucyBwZXIgY2VsbCB0eXBlIGFuZCBjb25kaXRpb24KCmBgYHtyfQojIGludGVyYWN0aW9ucyBoYXZlIHRvIGJlIGFic2VudCBpbiBhdCBsZWFzdCBvbmUgY29uZGl0aW9uCnBsb3RfZGYgPSBjdF9nX2NvbmRfYW5uW2N0X2dfY29uZF9hbm4kY2VsbHR5cGVzICVpbiUgYygiU3RlbGxhdGUgY2VsbHMiLCAiTFNFQyIsICJLdXBmZmVyIGNlbGxzIiwgImNEQ3MiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBEQ3MiLCAiRW5kb3RoZWxpYWwgY2VsbHMgKG5vbi1MU0VDKSIpICYgCiAgICAgICAgICAgICAgICAgICAgICAgICAgY3RfZ19jb25kX2FubiRkZXNjcmlwdGlvbiAlaW4lIGMoIkVDTSIsICJpbmZsYW1tYXRpb24iLCAibWlncmF0aW9uIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiZGV2ZWxvcG1lbnQiLCAiaW1tdW5lIGFjdGl2aXR5IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImltbXVuZSBzdXBwcmVzc2lvbiIsICJpbW11bmUgcmVndWxhdGlvbiIpLF0KcGxvdF9kZiRkZXNjcmlwdGlvbiA9IGdzdWIoIiAiLCAiXG4iLCBwbG90X2RmJGRlc2NyaXB0aW9uLCBmaXhlZCA9IFQpCnBsb3RfZGYkY2VsbHR5cGVzID0gZ3N1YigiICgiLCAiXG4oIiwgcGxvdF9kZiRjZWxsdHlwZXMsIGZpeGVkID0gVCkKcGxvdF9kZiRkZXNjcmlwdGlvbltncmVwbCgiaW1tdW5lIiwgcGxvdF9kZiRkZXNjcmlwdGlvbikgfCAKICAgICAgICAgICAgICAgICAgICAgIGdyZXBsKCJpbmZsYW1tIiwgcGxvdF9kZiRkZXNjcmlwdGlvbildID0gImltbXVuZSIKYmFyX2Z1bmNfc3ViID0gZ2dwbG90KHBsb3RfZGYsIGFlcyh4ID0gY29uZGl0aW9uLCBmaWxsID0gY29uZGl0aW9uKSkrCiAgZmFjZXRfZ3JpZChjZWxsdHlwZXN+ZGVzY3JpcHRpb24sIHNjYWxlcyA9ICJmcmVlX3kiKSsKICBnZW9tX2JhcigpKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNvbGNvbmQpKwogIHRoZW1lX2NsYXNzaWMoKSsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEsIHZqdXN0ID0gMSwgc2l6ZSA9IDcsIGNvbG91ciA9ICJibGFjayIpLAogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSA2LjMsIGNvbG91ciA9ICJibGFjayIpLAogICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDcpLAogICAgICAgIGF4aXMubGluZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJibGFjayIpLAogICAgICAgIHBhbmVsLmdyaWQubWFqb3IueSA9IGVsZW1lbnRfbGluZSgpLAogICAgICAgIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDcpLAogICAgICAgIHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXNwZWN0LnJhdGlvID0gMSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCgpwZGYoImZpZ3VyZV9wYW5lbHNfcmV2MS9maWdfY29tbS9tYWluRmlnX2Z1bmNQYXJ0LnBkZiIsIGhlaWdodCA9IDUuNSwgd2lkdGggPSA0LjUpCnByaW50KGJhcl9mdW5jX3N1YikKZGV2Lm9mZigpCgpwbG90X2RmID0gY3RfZ19jb25kX2FubgpwbG90X2RmJGRlc2NyaXB0aW9uID0gZ3N1YigiICIsICJcbiIsIHBsb3RfZGYkZGVzY3JpcHRpb24sIGZpeGVkID0gVCkKcGxvdF9kZiRjZWxsdHlwZXMgPSBnc3ViKCIgKCIsICJcbigiLCBwbG90X2RmJGNlbGx0eXBlcywgZml4ZWQgPSBUKQpwbG90X2RmJGRlc2NyaXB0aW9uW2dyZXBsKCJpbW11bmUiLCBwbG90X2RmJGRlc2NyaXB0aW9uKSB8IAogICAgICAgICAgICAgICAgICAgICAgZ3JlcGwoImluZmxhbW0iLCBwbG90X2RmJGRlc2NyaXB0aW9uKV0gPSAiaW1tdW5lIgpiYXJfZnVuY19hbGwgPSBnZ3Bsb3QocGxvdF9kZiwgYWVzKHggPSBjb25kaXRpb24sIGZpbGwgPSBjb25kaXRpb24pKSsKICBmYWNldF9ncmlkKGNlbGx0eXBlc35kZXNjcmlwdGlvbiwgc2NhbGVzID0gImZyZWVfeSIpKwogIGdlb21fYmFyKCkrCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY29sY29uZCkrCiAgdGhlbWVfY2xhc3NpYygpKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSwgdmp1c3QgPSAxLCBzaXplID0gNywgY29sb3VyID0gImJsYWNrIiksCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYuMywgY29sb3VyID0gImJsYWNrIiksCiAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gNyksCiAgICAgICAgYXhpcy5saW5lID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImJsYWNrIiksCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvci55ID0gZWxlbWVudF9saW5lKCksCiAgICAgICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gNyksCiAgICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBhc3BlY3QucmF0aW8gPSAxLzIsCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQoKcGRmKCJmaWd1cmVfcGFuZWxzX3JldjEvZmlnX2NvbW0vc3VwcEZpZ19jb3VudHNGdW5jLnBkZiIsIHBhcGVyID0gImE0Iiwgd2lkdGggPSA5LCBoZWlnaHQgPSAxMy41KQpwcmludChiYXJfZnVuY19hbGwpCmRldi5vZmYoKQpgYGAKCkludGVyYWN0aW9uIGZ1bmN0aW9ucyBwZXIgY2VsbCB0eXBlIGFuZCBjb25kaXRpb24gKHVzaW5nIGFsbCBpbnRlcmFjdGlvbnMpCgpgYGB7cn0KcGxvdF9kZiA9IFJlZHVjZShyYmluZCwgcmVmb3JtX2xpc3RbMTozXSkKcGxvdF9kZiRjb25kID0gYyhyZXAoImhlYWx0aHkiLCBucm93KHJlZm9ybV9saXN0JGhlYWx0aHkpKSwgCiAgICAgICAgICAgICAgICAgcmVwKCJlbWJvbGlzZWQiLCBucm93KHJlZm9ybV9saXN0JGVtYm9saXNlZCkpLCAKICAgICAgICAgICAgICAgICByZXAoInJlZ2VuZXJhdGluZyIsIG5yb3cocmVmb3JtX2xpc3QkcmVnZW5lcmF0aW5nKSkpCnBsb3RfZGYgPSB1bmlxdWUocGxvdF9kZikKcGxvdF9kZiA9IGRhdGEuZnJhbWUocmJpbmQoYXMubWF0cml4KHBsb3RfZGZbLGMoMSwyLDgpXSksIGFzLm1hdHJpeChwbG90X2RmWyxjKDEsMyw4KV0pKSkKcGxvdF9kZiA9IG1lcmdlKHBsb3RfZGYsIGludGVyX2Fubm90LCBieSA9IDEsIGFsbC54ID0gVCkKY29sbmFtZXMocGxvdF9kZikgPSBjKCJpbnRlcmFjdGlvbiIsICJjZWxsdHlwZXMiLCAiY29uZGl0aW9uIiwgImRlc2NyaXB0aW9uIikKCnBsb3RfZGYkZGVzY3JpcHRpb24gPSBnc3ViKCIgIiwgIlxuIiwgcGxvdF9kZiRkZXNjcmlwdGlvbiwgZml4ZWQgPSBUKQpwbG90X2RmJGNlbGx0eXBlcyA9IGdzdWIoIiAoIiwgIlxuKCIsIHBsb3RfZGYkY2VsbHR5cGVzLCBmaXhlZCA9IFQpCnBsb3RfZGYkZGVzY3JpcHRpb25bZ3JlcGwoImltbXVuZSIsIHBsb3RfZGYkZGVzY3JpcHRpb24pIHwgCiAgICAgICAgICAgICAgICAgICAgICBncmVwbCgiaW5mbGFtbSIsIHBsb3RfZGYkZGVzY3JpcHRpb24pXSA9ICJpbW11bmUiCmJhcl9mdW5jX2FsbCA9IGdncGxvdChwbG90X2RmLCBhZXMoeCA9IGNvbmRpdGlvbiwgZmlsbCA9IGNvbmRpdGlvbikpKwogIGZhY2V0X2dyaWQoZGVzY3JpcHRpb25+Y2VsbHR5cGVzLCBzY2FsZXMgPSAiZnJlZV95IikrCiAgZ2VvbV9iYXIoKSsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjb2xjb25kKSsKICB0aGVtZV9jbGFzc2ljKCkrCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxLCB2anVzdCA9IDEsIHNpemUgPSA3LCBjb2xvdXIgPSAiYmxhY2siKSwKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gNi4zLCBjb2xvdXIgPSAiYmxhY2siKSwKICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA3KSwKICAgICAgICBheGlzLmxpbmUgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiYmxhY2siKSwKICAgICAgICBwYW5lbC5ncmlkLm1ham9yLnkgPSBlbGVtZW50X2xpbmUoKSwKICAgICAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA3KSwKICAgICAgICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGFzcGVjdC5yYXRpbyA9IDEsCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQpgYGAKCkdTRUEgcXZhbHVlIGZvciBjaGFuZ2luZyBpbnRlcmFjdGlvbnMgKHVzaW5nIGFsbCkKCmBgYHtyfQpwbG90X2RmID0gUmVkdWNlKHJiaW5kLCBhbGxfZ3NlYV9saXN0KQpwbG90X2RmJHEudmFsID0gLWxvZzEwKHBsb3RfZGYkcS52YWwrMC4wMDAwMDA1KSoocGxvdF9kZiRzc2NvcmUvYWJzKHBsb3RfZGYkc3Njb3JlKSkKcGxvdF9kZiRjb21wID0gZmFjdG9yKHBsb3RfZGYkY29tcCwgbGV2ZWxzID0gcmV2KGMoImhlIiwiaHIiLCJlciIpKSkKbSA9IHRhcHBseShwbG90X2RmJHEudmFsLCBwbG90X2RmJGdyb3VwLG1lYW4pCnBsb3RfZGYkZ3JvdXAgPSBmYWN0b3IocGxvdF9kZiRncm91cCwgbGV2ZWxzID0gbmFtZXMobSlbb3JkZXIobSwgZGVjcmVhc2luZyA9IEYpXSkKcGxvdF9kZiA9IHBsb3RfZGZbcGxvdF9kZiRjb21wIT0iZXIiLF0KcGxvdF9kZiRjb21wID0gYXMuY2hhcmFjdGVyKHBseXI6OnJldmFsdWUocGxvdF9kZiRjb21wLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYygiaHIiID0gInJlZ2VuZXJhdGluZyIsICJoZSIgPSAiZW1ib2xpc2VkIiwgImVyIiA9ICJub3RoaW5nIikpKQpwbG90X2RmJGNvbXAgPSBmYWN0b3IocGxvdF9kZiRjb21wLCBsZXZlbHMgPSBjKCJyZWdlbmVyYXRpbmciLCAiZW1ib2xpc2VkIikpCgpnc2VhcGx0ID0gZ2dwbG90KHBsb3RfZGYsIGFlcyh4ID0gcS52YWwsIHkgPSBncm91cCwgZmlsbCA9IGNvbXApKSsKICBnZW9tX2NvbChwb3NpdGlvbiA9ICJkb2RnZSIpKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGMobG9nMTAoMC4wNSksIC1sb2cxMCgwLjA1KSksIGxpbmV0eXBlID0gImRhc2hlZCIpKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGMoMCkpKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNvbGNvbmQsIGRyb3AgPSBUKSsKICBndWlkZXMoZmlsbCA9IGd1aWRlX2xlZ2VuZCh0aXRsZSA9ICJoZWFsdGh5IHZzIiwgcmV2ZXJzZSA9IFQpKSsKICBsYWJzKHggPSAicS12YWx1ZSB4IHNjb3JlIHNpZ25hbCIsIHkgPSAiaW50ZXJhY3Rpb24gdHlwZSIsIGZpbGwgPSAiY29tcGFyaXNvbiIpKwogIHRoZW1lX2J3KCkrCiAgdGhlbWUoYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KGNvbG91ciA9ICJibGFjayIsIHNpemUgPSA3KSwKICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KGNvbG91ciA9ICJibGFjayIsIHNpemUgPSA3LjUpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9IGMoMCwxKSwKICAgICAgICBsZWdlbmQuanVzdGlmaWNhdGlvbiA9IGMoLTAuMDUsMS4wNSksCiAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA3LjUpLAogICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA3KSwKICAgICAgICBsZWdlbmQubWFyZ2luID0gbWFyZ2luKDAsMCwwLDApLAogICAgICAgIGxlZ2VuZC5rZXkuc2l6ZSA9IHVuaXQoMC4zNSwgImNtIikpCgpwZGYoImZpZ3VyZV9wYW5lbHNfcmV2MS9maWdfY29tbS9tYWluRmlnX2Z1bmNHU0VBLnBkZiIsIGhlaWdodCA9IDIuMiwgd2lkdGggPSAyLjg1KQpwcmludChnc2VhcGx0KQpkZXYub2ZmKCkKYGBgCgpJbnRlcmFjdGlvbiBleHByZXNzaW9uIG1hdHJpY2VzCgpgYGB7cn0KZ3JhZGV4cGNvbCA9IGMoIiNmM2VkZmYiLCAiI2VjYzhmYSIsICIjOWU0MmQ0IiwgIiM3OTJmOTEiKQoKZmlsdEZ1bmMgPSBmdW5jdGlvbih4LCBtdXR0aHIgPSAwLCBleHB0aHIgPSAwLjEyLCBtaW5jdCA9IDMpewogIGNvbGRmID0geFsoeCRtdXRJbmZvX2hlPD1tdXR0aHIgfCB4JG11dEluZm9faHI8PW11dHRociksMTo4XQogIGNvbGRmID0geFssMTo4XQogIGNvbGRmJGludGxyID0gcGFzdGUwKGNvbGRmJGxyMSwgIiAtXG4gIiwgY29sZGYkbHIyKQogIGNvbGRmID0gdW5pcXVlKGNvbGRmWyxjKDIsMyw5LDY6OCldKQogIG5pbnQgPSB0YWJsZShjb2xkZiRpbnRscikKICBjb2xkZiA9IGNvbGRmW2FwcGx5KGNvbGRmWyw0OjZdLCAxLCBmdW5jdGlvbih4KSBhbnkoeD49ZXhwdGhyKSkgJiAKICAgICAgICAgICAgICAgICAgKGNvbGRmJGludGxyICVpbiUgbmFtZXMobmludClbbmludD4xXSB8IGFwcGx5KGNvbGRmWyw0OjZdLCAxLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uKHgpIGFueSh4Pj1leHB0aHIqOCkpKSxdCiAgY29sZGYgPSBkYXRhLnRhYmxlOjpyYmluZGxpc3QobGlzdChyZXNoYXBlMjo6bWVsdChjb2xkZlssYygzLDEsNDo2KV0pLCAKICAgICAgICAgICAgICAgICAgICAgICAgIHJlc2hhcGUyOjptZWx0KGNvbGRmWyxjKDMsMiw0OjYpXSkpLCB1c2UubmFtZXMgPSBGKQogIGNvbGRmJHZhcmlhYmxlID0gdW5saXN0KGxhcHBseShzdHJzcGxpdChhcy5jaGFyYWN0ZXIoY29sZGYkdmFyaWFibGUpLCAiXyIpLCBmdW5jdGlvbih4KSB4WzFdKSkKICBjb2xkZiR2YXJpYWJsZSA9IGZhY3Rvcihjb2xkZiR2YXJpYWJsZSwgbGV2ZWxzID0gYygiaGVhbHRoeSIsICJlbWJvbGlzZWQiLCJyZWdlbmVyYXRpbmciKSkKICBjb2xkZiA9IGNvbGRmW29yZGVyKGNvbGRmJHZhbHVlLCBkZWNyZWFzaW5nID0gVCksXQogIGNvbGRmID0gY29sZGZbIWR1cGxpY2F0ZWQoY29sZGZbLDE6M10pLF0KICBjb2xkZiRjdDEgPSBnc3ViKCJFbmRvdGhlbGlhbCBjZWxscyIsICJFQyIsIGNvbGRmJGN0MSkKICBjb2xkZiRpbnRsciA9IGdzdWIoInJlY2VwdG9yIiwgIiIsIGNvbGRmJGludGxyKQogIG5jdCA9IHRhYmxlKGNvbGRmJGN0MSkKICBjb2xkZiA9IGNvbGRmW2NvbGRmJGN0MSAlaW4lIG5hbWVzKG5jdClbbmN0Pj1taW5jdCozXSxdCiAgbmludCA9IHRhYmxlKGNvbGRmJGludGxyKQogIGNvbGRmID0gY29sZGZbY29sZGYkaW50bHIgJWluJSBuYW1lcyhuaW50KVtuaW50PjNdLF0KICByZXR1cm4oY29sZGYpCn0KcGx0RnVuYyA9IGZ1bmN0aW9uKHgpewogIHBsdCA9IGdncGxvdCh4LCBhZXMoeCA9IHZhcmlhYmxlLCB5ID0gY3QxLCBmaWxsID0gdmFsdWUpKSsKICAgIGZhY2V0X2dyaWQoaW50bHJ+Liwgc2NhbGVzID0gImZyZWVfeSIsIHNwYWNlID0gImZyZWVfeSIpKwogICAgZ2VvbV90aWxlKCkrCiAgICBzY2FsZV94X2Rpc2NyZXRlKGV4cGFuZCA9IGMoMCwwKSkrCiAgICBzY2FsZV9maWxsX2dyYWRpZW50bihjb2xvcnMgPSBncmFkZXhwY29sKSsKICAgIGd1aWRlcyhmaWxsID0gZ3VpZGVfY29sb3VyYmFyKGJhcndpZHRoID0gdW5pdCgwLjQsICJjbSIpKSkrCiAgICBsYWJzKHggPSAiQ29uZGl0aW9uIiwgeSA9ICJDZWxsIHR5cGUiLCBmaWxsID0gIm1lYW4gZXhwIikrCiAgICB0aGVtZV9jbGFzc2ljKCkrCiAgICB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChjb2xvdXIgPSAiYmxhY2siLCBzaXplID0gNyksCiAgICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChjb2xvdXIgPSAiYmxhY2siLCBzaXplID0gNi41LCBhbmdsZSA9IC0zMCwgaGp1c3QgPSAwLCB2anVzdCA9IDEpLAogICAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gNyksCiAgICAgICAgICBheGlzLmxpbmUgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibGVmdCIsCiAgICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDcpLAogICAgICAgICAgbGVnZW5kLmJveC5tYXJnaW4gPSBtYXJnaW4oMCwwLDAsMCksCiAgICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gNiksCiAgICAgICAgICBzdHJpcC50ZXh0LnkgPSBlbGVtZW50X3RleHQoYW5nbGUgPSAwLCBzaXplID0gNyxtYXJnaW4gPSBtYXJnaW4oMCwwLDAsMyksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhqdXN0ID0gMC41LCBmYWNlID0gImJvbGQiKSwKICAgICAgICAgIHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCkpCiAgcmV0dXJuKHBsdCkKfQpwbHRGdW5jID0gZnVuY3Rpb24oeCl7CiAgcGx0ID0gZ2dwbG90KHgsIGFlcyh5ID0gdmFyaWFibGUsIHggPSBjdDEsIGZpbGwgPSB2YWx1ZSkpKwogICAgZmFjZXRfZ3JpZCgufmludGxyLCBzY2FsZXMgPSAiZnJlZV94Iiwgc3BhY2UgPSAiZnJlZV94IikrCiAgICBnZW9tX3RpbGUoKSsKICAgIHNjYWxlX3lfZGlzY3JldGUoZXhwYW5kID0gYygwLDApLCBsaW1pdHMgPSByZXYobGV2ZWxzKHgkdmFyaWFibGUpKSkrCiAgICBzY2FsZV9maWxsX2dyYWRpZW50bihjb2xvcnMgPSBncmFkZXhwY29sKSsKICAgIGd1aWRlcyhmaWxsID0gZ3VpZGVfY29sb3VyYmFyKGJhcmhlaWdodCA9IHVuaXQoMC40LCAiY20iKSkpKwogICAgbGFicyh5ID0gIkNvbmRpdGlvbiIsIHggPSAiQ2VsbCB0eXBlIiwgZmlsbCA9ICJtZWFuIGV4cCIpKwogICAgdGhlbWVfY2xhc3NpYygpKwogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoY29sb3VyID0gImJsYWNrIiwgc2l6ZSA9IDcsIGFuZ2xlID0gNDUsIGhqdXN0ID0gMSwgdmp1c3QgPSAxKSwKICAgICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KGNvbG91ciA9ICJibGFjayIsIHNpemUgPSA2LjUpLAogICAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gNyksCiAgICAgICAgICBheGlzLmxpbmUgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwKICAgICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gNyksCiAgICAgICAgICBsZWdlbmQuYm94Lm1hcmdpbiA9IG1hcmdpbigwLDAsMCwwKSwKICAgICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA2KSwKICAgICAgICAgIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBzaXplID0gNywgbWFyZ2luID0gbWFyZ2luKDAsMCwzLDApLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoanVzdCA9IDAsIHZqdXN0ID0gMC41LCBmYWNlID0gImJvbGQiKSwKICAgICAgICAgIHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCkpCiAgcmV0dXJuKHBsdCkKfQoKaGVyX2FsbGludF9mID0gbWVyZ2UoaGVyX2FsbGludCRhbGwsIGludGVyX2Fubm90LCBieSA9IDEsIGFsbC54ID0gVCkKd3JpdGUuY3N2KGhlcl9hbGxpbnRfZlssYygxOjgsMjgpXSwgZmlsZSA9ICJmaWd1cmVfcGFuZWxzX3JldjEvZmlnX2NvbW0vYWxsX2ludGVyYWN0aW9uc19mdW5jdGlvbnMuY3N2IiwKICAgICAgICAgIGNvbC5uYW1lcyA9IFQsIHJvdy5uYW1lcyA9IEYsIHF1b3RlID0gRikKIyByZW1vdmUgYXV0b2NyaW5lCmhlcl9hbGxpbnRfZiA9IGhlcl9hbGxpbnRfZltoZXJfYWxsaW50X2YkY3QxIT1oZXJfYWxsaW50X2YkY3QyLF0KaGVyX2FsbGludF9mID0gaGVyX2FsbGludF9mWyFpcy5uYShoZXJfYWxsaW50X2YkZnVuY3QpLF0KCiMgRUNNCnBsb3RfZGYgPSBmaWx0RnVuYyhoZXJfYWxsaW50X2ZbaGVyX2FsbGludF9mJGZ1bmN0PT0iRUNNIixdLCBleHB0aHIgPSAwLjE1KQplY21fcGx0ID0gcGx0RnVuYyhwbG90X2RmKQpwZGYoImZpZ3VyZV9wYW5lbHNfcmV2MS9maWdfY29tbS9tYWluRmlnX2VjbUludGVyYWN0LnBkZiIsIGhlaWdodCA9IDMsIHdpZHRoID0gNy41KQpwcmludChlY21fcGx0KQpkZXYub2ZmKCkKCiMgZGV2CnBsb3RfZGYgPSBmaWx0RnVuYyhoZXJfYWxsaW50X2ZbaGVyX2FsbGludF9mJGZ1bmN0PT0iZGV2ZWxvcG1lbnQiLF0sIGV4cHRociA9IDAuMTUpCmRldl9wbHQgPSBwbHRGdW5jKHBsb3RfZGYpCnBkZigiZmlndXJlX3BhbmVsc19yZXYxL2ZpZ19jb21tL21haW5GaWdfZGV2SW50ZXJhY3QucGRmIiwgaGVpZ2h0ID0gMywgd2lkdGggPSA3LjUpCnByaW50KGRldl9wbHQpCmRldi5vZmYoKQpgYGAKCk5ldHdvcmsgcGxvdHMgLSBNRFMKCmBgYHtyfQpwbHRib3RoID0gZ2dwbG90KCkrCiAgZ2VvbV9wb2ludChkYXRhID0gcG9pbnRfY29uZF9kZiwgbWFwcGluZyA9IGFlcyh4ID0gWDEsIHkgPSBYMiwgY29sb3VyID0gY3QyKSwgCiAgICAgICAgICAgICBhbHBoYSA9IDAuNiwgc2hvdy5sZWdlbmQgPSBOQSwgc2l6ZSA9IDEuMykrCiAgZ2VvbV9zZWdtZW50KGRhdGEgPSBwZV9sW1syXV0sIAogICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSBYMS54LCB4ZW5kID0gWDEueSwgeSA9IFgyLngsIHllbmQgPSBYMi55LCBzaXplID0gRnJlcSksIAogICAgICAgICAgICAgICBhbHBoYSA9IDAuMTUsIHNob3cubGVnZW5kID0gRikrCiAgZ2VvbV9wb2ludChkYXRhID0gcGVfbFtbMV1dLCAKICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IFgxLCB5ID0gWDIsIGZpbGwgPSBjdCksIAogICAgICAgICAgICAgYWxwaGEgPSAxLCBwY2ggPSAyMSwgc2l6ZSA9IDQpKwogIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gMi4zKSkpKwogIHNjYWxlX3NpemVfY29udGludW91cyhyYW5nZSA9IGMoMCwgNCksIGxpbWl0cyA9IHJhbmdlKHBlX2xbWzJdXSRGcmVxKSkrCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjb2xzbWFqb3IpKwogICNzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjb2xzYWxsY3QpKwogIHRoZW1lX2NsYXNzaWMoKSsgCiAgdGhlbWUoYXNwZWN0LnJhdGlvID0gMSwgCiAgICAgICAgYXhpcy5saW5lID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGxlZ2VuZC5rZXkuc2l6ZSA9IHVuaXQoMC4zNSwgImNtIiksCiAgICAgICAgbGVnZW5kLnNwYWNpbmcueSA9IHVuaXQoMC4xLCAiY20iKSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCnBkZigiZmlndXJlX3BhbmVsc19yZXYxL2ZpZ19jb21tL21haW5GaWdfaW5ldF9jb25kX2FsbC5wZGYiLCAKICAgIGhlaWdodCA9IDMuMSwgd2lkdGggPSA1LjIsIHVzZURpbmdiYXRzID0gRikKcHJpbnQocGx0Ym90aCkKZGV2Lm9mZigpCgpwbHRfY29uZF9sX2NoID0gbGlzdCgpCmZvcihjYyBpbiB1bmlxdWUocGVfY29uZF9sX2NoW1syXV0kY29uZGl0aW9uKSl7CiAgcGx0X2NvbmRfbF9jaFtbY2NdXSA9IGdncGxvdCgpKwogICAgZ2VvbV9zZWdtZW50KGRhdGEgPSBwZV9jb25kX2xfY2hbWzJdXVtwZV9jb25kX2xfY2hbWzJdXSRjb25kaXRpb249PWNjLF0sIAogICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IFgxLngsIHhlbmQgPSBYMS55LCB5ID0gWDIueCwgeWVuZCA9IFgyLnksIHNpemUgPSBGcmVxLCBhbHBoYSA9IEZyZXEpKSsKICAgIGdlb21fcG9pbnQoZGF0YSA9IHBlX2NvbmRfbF9jaFtbMV1dLCAKICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0gWDEsIHkgPSBYMiwgZmlsbCA9IGN0KSwgCiAgICAgICAgICAgICAgIGFscGhhID0gMSwgcGNoID0gMjEsIHNpemUgPSA0KSsKICAgIHNjYWxlX3NpemVfY29udGludW91cyhyYW5nZSA9IGMoMCwgNCksIGxpbWl0cyA9IHJhbmdlKHBlX2NvbmRfbF9jaFtbMl1dJEZyZXEpKSsKICAgIHNjYWxlX2FscGhhX2NvbnRpbnVvdXMocmFuZ2UgPSBjKDAsIDEpLCBsaW1pdHMgPSByYW5nZShwZV9jb25kX2xfY2hbWzJdXSRGcmVxKSkrCiAgICAjc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY29sc2FsbGN0KSsKICAgIGxhYnModGl0bGUgPSBjYykrCiAgICBndWlkZXMoc2l6ZSA9IGd1aWRlX2xlZ2VuZChkaXJlY3Rpb24gPSAiaG9yaXpvbnRhbCIsIG5yb3cgPSAyKSwKICAgICAgICAgICBhbHBoYSA9IGd1aWRlX2xlZ2VuZChkaXJlY3Rpb24gPSAiaG9yaXpvbnRhbCIsIG5yb3cgPSAyKSkrCiAgICB0aGVtZV9jbGFzc2ljKCkrIAogICAgdGhlbWUoYXNwZWN0LnJhdGlvID0gMSwgCiAgICAgICAgICBheGlzLmxpbmUgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImJsYWNrIiksCiAgICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICBsZWdlbmQua2V5LnNpemUgPSB1bml0KDAuMzUsICJjbSIpLAogICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQp9CnBsdF9jb25kX2xfY2hbWyJsZWciXV0gPSBjb3dwbG90OjpnZXRfbGVnZW5kKHBsdF9jb25kX2xfY2hbWyJoZWFsdGh5Il1dKQoKcGRmKCJmaWd1cmVfcGFuZWxzX3JldjEvZmlnX2NvbW0vbWFpbkZpZ19pbmV0X2NvbmRfbWVkaWFuLnBkZiIsIGhlaWdodCA9IDMuMiwgd2lkdGggPSA1LCB1c2VEaW5nYmF0cyA9IEYpCnByaW50KHBsdF9jb25kX2xfY2gkaGVhbHRoeSkKcHJpbnQocGx0X2NvbmRfbF9jaCRlbWJvbGlzZWQpCnByaW50KHBsdF9jb25kX2xfY2gkcmVnZW5lcmF0aW5nKQpkZXYub2ZmKCkKYGBgCgpOZXR3b3JrIHBsb3RzIHdpdGggbWlkZGxlIGNlbGwgdHlwZSByZXNvbHV0aW9uIC0gTURTCgpgYGB7cn0KcGx0Ym90aCA9IGdncGxvdCgpKwogIGdlb21fcG9pbnQoZGF0YSA9IHBvaW50X2NvbmRfZGYsIG1hcHBpbmcgPSBhZXMoeCA9IFgxLCB5ID0gWDIsIGNvbG91ciA9IGN0MiksIAogICAgICAgICAgICAgYWxwaGEgPSAwLjYsIHNob3cubGVnZW5kID0gTkEsIHNpemUgPSAxLjMpKwogIGdlb21fc2VnbWVudChkYXRhID0gcGVfbWlkX2xbWzJdXSwgCiAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IFgxLngsIHhlbmQgPSBYMS55LCB5ID0gWDIueCwgeWVuZCA9IFgyLnksIHNpemUgPSBGcmVxKSwgCiAgICAgICAgICAgICAgIGFscGhhID0gMC4xNSwgc2hvdy5sZWdlbmQgPSBGKSsKICBnZW9tX3BvaW50KGRhdGEgPSBwZV9taWRfbFtbMV1dLCAKICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IFgxLCB5ID0gWDIsIGZpbGwgPSBjdF9taWQpLCAKICAgICAgICAgICAgIGFscGhhID0gMSwgcGNoID0gMjEsIHNpemUgPSA0KSsKICBndWlkZXMoY29sb3VyID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZSA9IDIuMykpKSsKICBzY2FsZV9zaXplX2NvbnRpbnVvdXMocmFuZ2UgPSBjKDAsIDQpLCBsaW1pdHMgPSByYW5nZShwZV9taWRfbFtbMl1dJEZyZXEpKSsKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGNvbHNtYWpvcikrCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY29sc21pZGN0KSsKICB0aGVtZV9jbGFzc2ljKCkrIAogIHRoZW1lKGFzcGVjdC5yYXRpbyA9IDEsIAogICAgICAgIGF4aXMubGluZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpY2tzID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBsZWdlbmQua2V5LnNpemUgPSB1bml0KDAuMzUsICJjbSIpLAogICAgICAgIGxlZ2VuZC5zcGFjaW5nLnkgPSB1bml0KDAuMSwgImNtIiksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQpwZGYoImZpZ3VyZV9wYW5lbHNfcmV2MS9maWdfY29tbS9tYWluRmlnX2luZXRfY29uZF9taWQucGRmIiwgCiAgICBoZWlnaHQgPSAzLjEsIHdpZHRoID0gNS4yLCB1c2VEaW5nYmF0cyA9IEYpCnByaW50KHBsdGJvdGgpCmRldi5vZmYoKQoKcGx0X2NvbmRfbF9jaCA9IGxpc3QoKQpmb3IoY2MgaW4gdW5pcXVlKHBlX2NvbmRfbF9taWRbWzJdXSRjb25kaXRpb24pKXsKICBwbHRfY29uZF9sX2NoW1tjY11dID0gZ2dwbG90KCkrCiAgICBnZW9tX3NlZ21lbnQoZGF0YSA9IHBlX2NvbmRfbF9taWRbWzJdXVtwZV9jb25kX2xfbWlkW1syXV0kY29uZGl0aW9uPT1jYyxdLCAKICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSBYMS54LCB4ZW5kID0gWDEueSwgeSA9IFgyLngsIHllbmQgPSBYMi55LCBzaXplID0gRnJlcSwgYWxwaGEgPSBGcmVxKSkrCiAgICBnZW9tX3BvaW50KGRhdGEgPSBwZV9jb25kX2xfbWlkW1sxXV0sIAogICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSBYMSwgeSA9IFgyLCBmaWxsID0gY3RfbWlkKSwgCiAgICAgICAgICAgICAgIGFscGhhID0gMSwgcGNoID0gMjEsIHNpemUgPSA0KSsKICAgIHNjYWxlX3NpemVfY29udGludW91cyhyYW5nZSA9IGMoMCwgNCksIGxpbWl0cyA9IHJhbmdlKHBlX2NvbmRfbF9taWRbWzJdXSRGcmVxKSkrCiAgICBzY2FsZV9hbHBoYV9jb250aW51b3VzKHJhbmdlID0gYygwLCAxKSwgbGltaXRzID0gcmFuZ2UocGVfY29uZF9sX21pZFtbMl1dJEZyZXEpKSsKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNvbHNtaWRjdCkrCiAgICBsYWJzKHRpdGxlID0gY2MpKwogICAgZ3VpZGVzKHNpemUgPSBndWlkZV9sZWdlbmQoZGlyZWN0aW9uID0gImhvcml6b250YWwiLCBucm93ID0gMiksCiAgICAgICAgICAgYWxwaGEgPSBndWlkZV9sZWdlbmQoZGlyZWN0aW9uID0gImhvcml6b250YWwiLCBucm93ID0gMikpKwogICAgdGhlbWVfY2xhc3NpYygpKyAKICAgIHRoZW1lKGFzcGVjdC5yYXRpbyA9IDEsIAogICAgICAgICAgYXhpcy5saW5lID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJibGFjayIpLAogICAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgbGVnZW5kLmtleS5zaXplID0gdW5pdCgwLjM1LCAiY20iKSkKfQoKcGRmKCJmaWd1cmVfcGFuZWxzX3JldjEvZmlnX2NvbW0vbWFpbkZpZ19pbmV0X2NvbmRfbWVkaWFuX21pZC5wZGYiLCAKICAgIGhlaWdodCA9IDMuMiwgd2lkdGggPSA1LCB1c2VEaW5nYmF0cyA9IEYpCnByaW50KHBsdF9jb25kX2xfY2gkaGVhbHRoeSkKcHJpbnQocGx0X2NvbmRfbF9jaCRlbWJvbGlzZWQpCnByaW50KHBsdF9jb25kX2xfY2gkcmVnZW5lcmF0aW5nKQpkZXYub2ZmKCkKYGBgCgpOZXR3b3JrIHBsb3RzIC0gVU1BUAoKYGBge3J9CnBsdGJvdGggPSBnZ3Bsb3QoKSsKICBnZW9tX3BvaW50KGRhdGEgPSBwb2ludF9jb25kX3VtYXBfZGYsIG1hcHBpbmcgPSBhZXMoeCA9IFgxLCB5ID0gWDIsIGNvbG91ciA9IGN0MiksIAogICAgICAgICAgICAgYWxwaGEgPSAwLjYsIHNob3cubGVnZW5kID0gTkEsIHNpemUgPSAxLjMpKwogIGdlb21fc2VnbWVudChkYXRhID0gcGVfdW1hcF9sW1syXV0sIAogICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSBYMS54LCB4ZW5kID0gWDEueSwgeSA9IFgyLngsIHllbmQgPSBYMi55LCBzaXplID0gRnJlcSksIAogICAgICAgICAgICAgICBhbHBoYSA9IDAuMTUsIHNob3cubGVnZW5kID0gRikrCiAgZ2VvbV9wb2ludChkYXRhID0gcGVfdW1hcF9sW1sxXV0sIAogICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0gWDEsIHkgPSBYMiwgZmlsbCA9IGN0KSwgCiAgICAgICAgICAgICBhbHBoYSA9IDEsIHBjaCA9IDIxLCBzaXplID0gNCkrCiAgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KHNpemUgPSAyLjMpKSkrCiAgc2NhbGVfc2l6ZV9jb250aW51b3VzKHJhbmdlID0gYygwLCA0KSwgbGltaXRzID0gcmFuZ2UocGVfbFtbMl1dJEZyZXEpKSsKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGNvbHNtYWpvcikrCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY29sc2FsbGN0KSsKICB0aGVtZV9jbGFzc2ljKCkrIAogIHRoZW1lKGFzcGVjdC5yYXRpbyA9IDEsIAogICAgICAgIGF4aXMubGluZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpY2tzID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBsZWdlbmQua2V5LnNpemUgPSB1bml0KDAuMzUsICJjbSIpLAogICAgICAgIGxlZ2VuZC5zcGFjaW5nLnkgPSB1bml0KDAuMSwgImNtIiksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQpwZGYoImZpZ3VyZV9wYW5lbHNfcmV2MS9maWdfY29tbS9tYWluRmlnX2luZXRfY29uZF91bWFwX2FsbC5wZGYiLCBoZWlnaHQgPSAzLjEsIHdpZHRoID0gNS4yLCB1c2VEaW5nYmF0cyA9IEYpCnByaW50KHBsdGJvdGgpCmRldi5vZmYoKQoKcGx0X2NvbmRfbF9jaCA9IGxpc3QoKQpmb3IoY2MgaW4gdW5pcXVlKHBlX3VtYXBfY29uZF9sX2NoW1syXV0kY29uZCkpewogIHBsdF9jb25kX2xfY2hbW2NjXV0gPSBnZ3Bsb3QoKSsKICAgIGdlb21fc2VnbWVudChkYXRhID0gcGVfdW1hcF9jb25kX2xfY2hbWzJdXVtwZV91bWFwX2NvbmRfbF9jaFtbMl1dJGNvbmQ9PWNjLF0sIAogICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IFgxLngsIHhlbmQgPSBYMS55LCB5ID0gWDIueCwgeWVuZCA9IFgyLnksIHNpemUgPSBGcmVxLCBhbHBoYSA9IEZyZXEpKSsKICAgIGdlb21fcG9pbnQoZGF0YSA9IHBlX3VtYXBfY29uZF9sX2NoW1sxXV0sIAogICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSBYMSwgeSA9IFgyLCBmaWxsID0gY3QpLCAKICAgICAgICAgICAgICAgYWxwaGEgPSAxLCBwY2ggPSAyMSwgc2l6ZSA9IDQpKwogICAgc2NhbGVfc2l6ZV9jb250aW51b3VzKHJhbmdlID0gYygwLCA0KSwgbGltaXRzID0gcmFuZ2UocGVfdW1hcF9jb25kX2xfY2hbWzJdXSRGcmVxKSkrCiAgICBzY2FsZV9hbHBoYV9jb250aW51b3VzKHJhbmdlID0gYygwLCAxKSwgbGltaXRzID0gcmFuZ2UocGVfdW1hcF9jb25kX2xfY2hbWzJdXSRGcmVxKSkrCiAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjb2xzYWxsY3QpKwogICAgbGFicyh0aXRsZSA9IGNjKSsKICAgIGd1aWRlcyhzaXplID0gZ3VpZGVfbGVnZW5kKGRpcmVjdGlvbiA9ICJob3Jpem9udGFsIiwgbnJvdyA9IDIpLAogICAgICAgICAgIGFscGhhID0gZ3VpZGVfbGVnZW5kKGRpcmVjdGlvbiA9ICJob3Jpem9udGFsIiwgbnJvdyA9IDIpKSsKICAgIHRoZW1lX2NsYXNzaWMoKSsgCiAgICB0aGVtZShhc3BlY3QucmF0aW8gPSAxLCAKICAgICAgICAgIGF4aXMubGluZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICBheGlzLnRpY2tzID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiYmxhY2siKSwKICAgICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgIGxlZ2VuZC5rZXkuc2l6ZSA9IHVuaXQoMC4zNSwgImNtIiksCiAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCn0KcGx0X2NvbmRfbF9jaFtbImxlZyJdXSA9IGNvd3Bsb3Q6OmdldF9sZWdlbmQocGx0X2NvbmRfbF9jaFtbImhlYWx0aHkiXV0pCgpwZGYoImZpZ3VyZV9wYW5lbHNfcmV2MS9maWdfY29tbS9tYWluRmlnX2luZXRfY29uZF91bWFwX21lZGlhbi5wZGYiLCBoZWlnaHQgPSAzLjIsIHdpZHRoID0gNSwgdXNlRGluZ2JhdHMgPSBGKQpwcmludChwbHRfY29uZF9sX2NoJGhlYWx0aHkpCnByaW50KHBsdF9jb25kX2xfY2gkZW1ib2xpc2VkKQpwcmludChwbHRfY29uZF9sX2NoJHJlZ2VuZXJhdGluZykKZGV2Lm9mZigpCmBgYAoKTmV0d29yayBwbG90cyB3aXRoIG1pZGRsZSBjZWxsIHR5cGUgcmVzb2x1dGlvbiAtIFVNQVAKCmBgYHtyfQpwbHRib3RoID0gZ2dwbG90KCkrCiAgZ2VvbV9wb2ludChkYXRhID0gcG9pbnRfY29uZF91bWFwX2RmLCBtYXBwaW5nID0gYWVzKHggPSBYMSwgeSA9IFgyLCBjb2xvdXIgPSBjdDIpLCAKICAgICAgICAgICAgIGFscGhhID0gMC42LCBzaG93LmxlZ2VuZCA9IE5BLCBzaXplID0gMS4zKSsKICBnZW9tX3NlZ21lbnQoZGF0YSA9IHBlX3VtYXBfbWlkX2xbWzJdXSwgCiAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IFgxLngsIHhlbmQgPSBYMS55LCB5ID0gWDIueCwgeWVuZCA9IFgyLnksIHNpemUgPSBGcmVxKSwgCiAgICAgICAgICAgICAgIGFscGhhID0gMC4xNSwgc2hvdy5sZWdlbmQgPSBGKSsKICBnZW9tX3BvaW50KGRhdGEgPSBwZV91bWFwX21pZF9sW1sxXV0sIAogICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0gWDEsIHkgPSBYMiwgZmlsbCA9IGN0X21pZCksIAogICAgICAgICAgICAgYWxwaGEgPSAxLCBwY2ggPSAyMSwgc2l6ZSA9IDQpKwogIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gMi4zKSkpKwogIHNjYWxlX3NpemVfY29udGludW91cyhyYW5nZSA9IGMoMCwgNCkpKwogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gY29sc21ham9yKSsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjb2xzbWlkY3QpKwogIHRoZW1lX2NsYXNzaWMoKSsgCiAgdGhlbWUoYXNwZWN0LnJhdGlvID0gMSwgCiAgICAgICAgYXhpcy5saW5lID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGxlZ2VuZC5rZXkuc2l6ZSA9IHVuaXQoMC4zNSwgImNtIiksCiAgICAgICAgbGVnZW5kLnNwYWNpbmcueSA9IHVuaXQoMC4xLCAiY20iKSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCnBkZigiZmlndXJlX3BhbmVsc19yZXYxL2ZpZ19jb21tL21haW5GaWdfaW5ldF9jb25kX3VtYXBfYWxsX21pZC5wZGYiLCBoZWlnaHQgPSAzLjEsIHdpZHRoID0gNS4yLCB1c2VEaW5nYmF0cyA9IEYpCnByaW50KHBsdGJvdGgpCmRldi5vZmYoKQoKcGx0X2NvbmRfbF9jaCA9IGxpc3QoKQpmb3IoY2MgaW4gdW5pcXVlKHBlX3VtYXBfY29uZF9sX21pZFtbMl1dJGNvbmQpKXsKICBwbHRfY29uZF9sX2NoW1tjY11dID0gZ2dwbG90KCkrCiAgICBnZW9tX3NlZ21lbnQoZGF0YSA9IHBlX3VtYXBfY29uZF9sX21pZFtbMl1dW3BlX3VtYXBfY29uZF9sX21pZFtbMl1dJGNvbmQ9PWNjLF0sIAogICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IFgxLngsIHhlbmQgPSBYMS55LCB5ID0gWDIueCwgeWVuZCA9IFgyLnksIHNpemUgPSBGcmVxLCBhbHBoYSA9IEZyZXEpKSsKICAgIGdlb21fcG9pbnQoZGF0YSA9IHBlX3VtYXBfY29uZF9sX21pZFtbMV1dLCAKICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0gWDEsIHkgPSBYMiwgZmlsbCA9IGN0X21pZCksIAogICAgICAgICAgICAgICBhbHBoYSA9IDEsIHBjaCA9IDIxLCBzaXplID0gNCkrCiAgICBzY2FsZV9zaXplX2NvbnRpbnVvdXMocmFuZ2UgPSBjKDAsIDQpLCBsaW1pdHMgPSByYW5nZShwZV91bWFwX2NvbmRfbF9taWRbWzJdXSRGcmVxKSkrCiAgICBzY2FsZV9hbHBoYV9jb250aW51b3VzKHJhbmdlID0gYygwLCAxKSwgbGltaXRzID0gcmFuZ2UocGVfdW1hcF9jb25kX2xfbWlkW1syXV0kRnJlcSkpKwogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY29sc21pZGN0KSsKICAgIGxhYnModGl0bGUgPSBjYykrCiAgICBndWlkZXMoc2l6ZSA9IGd1aWRlX2xlZ2VuZChkaXJlY3Rpb24gPSAiaG9yaXpvbnRhbCIsIG5yb3cgPSAyKSwKICAgICAgICAgICBhbHBoYSA9IGd1aWRlX2xlZ2VuZChkaXJlY3Rpb24gPSAiaG9yaXpvbnRhbCIsIG5yb3cgPSAyKSkrCiAgICB0aGVtZV9jbGFzc2ljKCkrIAogICAgdGhlbWUoYXNwZWN0LnJhdGlvID0gMSwgCiAgICAgICAgICBheGlzLmxpbmUgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImJsYWNrIiksCiAgICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICBsZWdlbmQua2V5LnNpemUgPSB1bml0KDAuMzUsICJjbSIpKQp9CnBsdF9jb25kX2xfY2hbWyJsZWciXV0gPSBjb3dwbG90OjpnZXRfbGVnZW5kKHBsdF9jb25kX2xfY2hbWyJoZWFsdGh5Il1dKQoKcGRmKCJmaWd1cmVfcGFuZWxzX3JldjEvZmlnX2NvbW0vbWFpbkZpZ19pbmV0X2NvbmRfdW1hcF9tZWRpYW5fbWlkLnBkZiIsIGhlaWdodCA9IDMuMiwgd2lkdGggPSA1LCB1c2VEaW5nYmF0cyA9IEYpCnByaW50KHBsdF9jb25kX2xfY2gkaGVhbHRoeSkKcHJpbnQocGx0X2NvbmRfbF9jaCRlbWJvbGlzZWQpCnByaW50KHBsdF9jb25kX2xfY2gkcmVnZW5lcmF0aW5nKQpkZXYub2ZmKCkKYGBgCgpIZWF0bWFwcyBmb3IgaW50ZXJhY3Rpb25zIHdpdGggaW1tdW5lIGNlbGxzCgpgYGB7cn0KIyBpbnRlcmFjdGlvbnMgdW5pcXVlIHRvIGhlYWx0aHkgb3IgdG8gZW1iL3JlZ2VuCmNvbXBoX2ludGVycyA9IGMoc2V0ZGlmZihpbnRlcl9kZiRoZWFsdGh5JGlkX2NwX2ludGVyYWN0aW9uLAogICAgICAgICAgICAgICAgICAgICAgICAgYyhpbnRlcl9kZiRlbWJvbGlzZWQkaWRfY3BfaW50ZXJhY3Rpb24sIGludGVyX2RmJHJlZ2VuZXJhdGluZyRpZF9jcF9pbnRlcmFjdGlvbikpLAogICAgICAgICAgICAgICAgIHNldGRpZmYoaW50ZXJfZGYkZW1ib2xpc2VkJGlkX2NwX2ludGVyYWN0aW9uLCBpbnRlcl9kZiRoZWFsdGh5JGlkX2NwX2ludGVyYWN0aW9uKSwKICAgICAgICAgICAgICAgICBzZXRkaWZmKGludGVyX2RmJHJlZ2VuZXJhdGluZyRpZF9jcF9pbnRlcmFjdGlvbiwgaW50ZXJfZGYkaGVhbHRoeSRpZF9jcF9pbnRlcmFjdGlvbikpCgplZGdlX21pbiA9IGVkZ2VfY29uZF9kZlssYygxOjQsOToxMildCmVkZ2VfbWluID0gbWVyZ2UoZWRnZV9taW4sIHVuaXF1ZShoZXJfYWxsaW50X2ZbLGMoMSwxMyldKSwgYnkueCA9IDMsIGJ5LnkgPSAxLCBhbGwueCA9IFQpCmVkZ2VfbWluID0gbWVyZ2UoZWRnZV9taW4sIHVuaXF1ZShoZXJfYWxsaW50X2ZbLGMoMSwxNyldKSwgYnkueCA9IDEsIGJ5LnkgPSAxLCBhbGwueCA9IFQpCmVkZ2VfbWluID0gZWRnZV9taW5bZWRnZV9taW4kbWFqX2cxPT0iSW1tdW5lIiB8IGVkZ2VfbWluJG1hal9nMj09IkltbXVuZSIsXQplZGdlX21pbiA9IGVkZ2VfbWluW2VkZ2VfbWluJGN0X2cxIT1lZGdlX21pbiRjdF9nMixdCmVkZ2VfbWluID0gZWRnZV9taW5bZWRnZV9taW4kaWRfY3BfaW50ZXJhY3Rpb24gJWluJSBjb21waF9pbnRlcnMsXQoKZGV2ZGYgPSBmaWx0RnVuYyhoZXJfYWxsaW50X2ZbaGVyX2FsbGludF9mJGZ1bmN0PT0iZGV2ZWxvcG1lbnQiLF0sIGV4cHRociA9IDAuMTUpCmVjbWRmID0gZmlsdEZ1bmMoaGVyX2FsbGludF9mW2hlcl9hbGxpbnRfZiRmdW5jdD09IkVDTSIsXSwgZXhwdGhyID0gMC4xNSkKCnBsb3RfZGYgPSBmaWx0RnVuYyhoZXJfYWxsaW50X2ZbaGVyX2FsbGludF9mJGlkX2NwX2ludGVyYWN0aW9uICVpbiUgdW5pcXVlKGVkZ2VfbWluJGlkX2NwX2ludGVyYWN0aW9uKSxdLAogICAgICAgICAgICAgICAgICAgZXhwdGhyID0gMC4wNywgbWluY3QgPSAyKQpwbG90X2RmID0gcGxvdF9kZlshKHBsb3RfZGYkaW50bHIgJWluJSBjKGRldmRmJGludGxyLCBlY21kZiRpbnRscikpLF0KaW1tX3BsdCA9IHBsdEZ1bmMocGxvdF9kZikKcGRmKCJmaWd1cmVfcGFuZWxzX3JldjEvZmlnX2NvbW0vbWFpbkZpZ19pbW11bmVOZXRJbnRlcmFjdF9tYW55LnBkZiIsIGhlaWdodCA9IDMsIHdpZHRoID0gMjApCnByaW50KGltbV9wbHQpCmRldi5vZmYoKQoKcGxvdF9kZiA9IGZpbHRGdW5jKGhlcl9hbGxpbnRfZltoZXJfYWxsaW50X2YkaWRfY3BfaW50ZXJhY3Rpb24gJWluJSB1bmlxdWUoZWRnZV9taW4kaWRfY3BfaW50ZXJhY3Rpb24pLF0sCiAgICAgICAgICAgICAgICAgICBleHB0aHIgPSAwLjMsIG1pbmN0ID0gMikKcGxvdF9kZiA9IHBsb3RfZGZbIShwbG90X2RmJGludGxyICVpbiUgYyhkZXZkZiRpbnRsciwgZWNtZGYkaW50bHIpKSxdCmltbV9wbHQgPSBwbHRGdW5jKHBsb3RfZGYpCnBkZigiZmlndXJlX3BhbmVsc19yZXYxL2ZpZ19jb21tL21haW5GaWdfaW1tdW5lTmV0SW50ZXJhY3QucGRmIiwgaGVpZ2h0ID0gMi44Niwgd2lkdGggPSA3LjEpCnByaW50KGltbV9wbHQpCmRldi5vZmYoKQpgYGAKCkhlYXRtYXBzIHdpdGggbnVtYmVyIG9mIGludGVyYWN0aW9ucyBwZXIgY29uZGl0aW9uCgpgYGB7cn0KY250c19saXN0ID0gbGlzdCgpCnRhYl9saXN0ID0gbGlzdCgpCmZvcihuIGluIG5hbWVzKGludGVyX2RmKVsxOjNdKXsKICBzdWJkZmN0ID0gdW5pcXVlKGludGVyX2RmW1tuXV1bLDE6M10pCiAgc3ViZGZjdCRjdDFbZ3JlcGwoIkxTRUNfIiwgc3ViZGZjdCRjdDEpXSA9ICJMU0VDIgogIHN1YmRmY3QkY3QyW2dyZXBsKCJMU0VDXyIsIHN1YmRmY3QkY3QyKV0gPSAiTFNFQyIKICBzdWJkZmN0JGN0MVtncmVwbCgiSGVwYXQiLCBzdWJkZmN0JGN0MSldID0gIkhlcGF0b2N5dGVzIgogIHN1YmRmY3QkY3QyW2dyZXBsKCJIZXBhdCIsIHN1YmRmY3QkY3QyKV0gPSAiSGVwYXRvY3l0ZXMiCiAgI3N1YmRmY3QkY3QxW2dyZXBsKCJub24tIiwgc3ViZGZjdCRjdDEpXSA9ICJFbmRvdGhlbGlhbCBjZWxsc1xuKG5vbi1MU0VDKSIKICAjc3ViZGZjdCRjdDJbZ3JlcGwoIm5vbi0iLCBzdWJkZmN0JGN0MildID0gIkVuZG90aGVsaWFsIGNlbGxzXG4obm9uLUxTRUMpIgogIHN1YmRmY3QgPSB1bmlxdWUoc3ViZGZjdCkKICBkZmN0ID0gdGFibGUoZGF0YS5mcmFtZSgiY3QxIiA9IGMoc3ViZGZjdCRjdDEsIHN1YmRmY3QkY3QyKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAiY3QyIiA9IGMoc3ViZGZjdCRjdDIsIHN1YmRmY3QkY3QxKSkpCiAgaGNsID0gaGNsdXN0KGRpc3QoZGZjdCksIG1ldGhvZCA9ICJ3YXJkLkQyIikKICBwbG90X2RmID0gZGF0YS5mcmFtZShkZmN0KQogIHBsb3RfZGYkY3QxID0gZmFjdG9yKHBsb3RfZGYkY3QxLCBsZXZlbHMgPSBsZXZlbHMobmV0X25hbWVzX2FsbCRWYXIxKSkKICBwbG90X2RmJGN0MiA9IGZhY3RvcihwbG90X2RmJGN0MiwgbGV2ZWxzID0gbGV2ZWxzKG5ldF9uYW1lc19hbGwkVmFyMSkpCiAgI3Bsb3RfZGYkY3QxID0gZmFjdG9yKHBsb3RfZGYkY3QxLCBsZXZlbHMgPSByZXYoYygiU3RlbGxhdGUgY2VsbHMiLCAiTFNFQyIsICJFbmRvdGhlbGlhbCBjZWxsc1xuKG5vbi1MU0VDKSIsCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiS3VwZmZlciBjZWxscyIsICJjRENzIiwgIk1hY3JvcGhhZ2VzIiwgIkNob2xhbmdpb2N5dGVzIiwKICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwRENzIiwgImFiLVQgY2VsbHMiLCAiSGVwYXRvY3l0ZXMiLCAiZ2QtVCBjZWxscyIsIAogICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkIgY2VsbHMiLCAiUGxhc21hYmxhc3RzIikpKQogICNwbG90X2RmJGN0MiA9IGZhY3RvcihwbG90X2RmJGN0MiwgbGV2ZWxzID0gcmV2KGMoIlN0ZWxsYXRlIGNlbGxzIiwgIkxTRUMiLCAiRW5kb3RoZWxpYWwgY2VsbHNcbihub24tTFNFQykiLAogICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkt1cGZmZXIgY2VsbHMiLCAiY0RDcyIsICJNYWNyb3BoYWdlcyIsICJDaG9sYW5naW9jeXRlcyIsCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicERDcyIsICJhYi1UIGNlbGxzIiwgIkhlcGF0b2N5dGVzIiwgImdkLVQgY2VsbHMiLCAKICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJCIGNlbGxzIiwgIlBsYXNtYWJsYXN0cyIpKSkKICBwbHRjbnRzID0gZ2dwbG90KHBsb3RfZGYsIGFlcyh4ID0gY3QxLCB5ID0gY3QyLCBzaXplID0gRnJlcSwgY29sb3VyID0gRnJlcSkpKwogICAgZ2VvbV9wb2ludCgpKwogICAgbGFicyh4ID0gImNlbGwgdHlwZSIsIHkgPSAiY2VsbCB0eXBlIiwgdGl0bGUgPSBuKSsKICAgIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9sZWdlbmQodGl0bGUgPSAiIyBpbnRlcmFjdGlvbnMiLCByZXZlcnNlID0gVCksIAogICAgICAgICAgIHNpemUgPSBndWlkZV9sZWdlbmQodGl0bGUgPSAiIyBpbnRlcmFjdGlvbnMiLCByZXZlcnNlID0gVCkpKwogICAgc2NhbGVfY29sb3VyX2dyYWRpZW50bihjb2xvcnMgPSBjKCIjZWRlZGVkIiwgIiNkZWViZjciLCAiIzllY2FlMSIsICIjYmNiZGRjIiwgIiM3NTZiYjEiKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpbWl0cyA9IGMoMCwgMjQwKSkrCiAgICBzY2FsZV9zaXplX2NvbnRpbnVvdXMobGltaXRzID0gYygwLCAyNDApKSsKICAgIHRoZW1lX2NsYXNzaWMoKSsKICAgIHRoZW1lKGFzcGVjdC5yYXRpbyA9IDEsCiAgICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJibGFjayIpLAogICAgICAgICAgYXhpcy5saW5lID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxLCB2anVzdCA9IDAuNCksCiAgICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoY29sb3VyID0gImJsYWNrIikpCiAgY250c19saXN0W1tuXV0gPSBwbHRjbnRzCiAgdGFiX2xpc3RbW25dXSA9IGRmY3QKfQpjbnRzX2xpc3QkbGVnZW5kID0gY293cGxvdDo6Z2V0X2xlZ2VuZChjbnRzX2xpc3QkaGVhbHRoeSkKY250c19saXN0JGhlYWx0aHkgPSBjbnRzX2xpc3QkaGVhbHRoeSt0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCmNudHNfbGlzdCRlbWJvbGlzZWQgPSBjbnRzX2xpc3QkZW1ib2xpc2VkK3RoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKY250c19saXN0JHJlZ2VuZXJhdGluZyA9IGNudHNfbGlzdCRyZWdlbmVyYXRpbmcrdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQoKcGRmKCJmaWd1cmVfcGFuZWxzX3JldjEvZmlnX2NvbW0vc3VwcEZpZ19jb3VudHNDb25kLnBkZiIsIGhlaWdodCA9IDE1LCB3aWR0aCA9IDE1KQpjbnRzX2xpc3RbWzFdXStjbnRzX2xpc3RbWzNdXStjbnRzX2xpc3RbWzJdXStjbnRzX2xpc3RbWzRdXSsgICAgICBwYXRjaHdvcms6OnBsb3RfbGF5b3V0KG5jb2wgPSAyKQpkZXYub2ZmKCkKYGBgCgpIZWF0bWFwcyB3aXRoIGRpZmZlcmVuY2UgaW4gbnVtYmVyIG9mIGludGVyYWN0aW9ucyB2cyBoZWFsdGh5CgpgYGB7cn0KZGlmZl9jbnRfbCA9IGxpc3QoKQpmb3IobiBpbiBjKCJlbWJvbGlzZWQiLCAicmVnZW5lcmF0aW5nIikpewogIGRpZl9kZiA9IHRhYl9saXN0W1tuXV0tdGFiX2xpc3QkaGVhbHRoeQogIGhjbCA9IGhjbHVzdChkaXN0KGRpZl9kZiksIG1ldGhvZCA9ICJ3YXJkLkQyIikKICBwbG90X2RmID0gZGF0YS5mcmFtZShkaWZfZGYpCiAgI3Bsb3RfZGYkY3QxID0gZmFjdG9yKHBsb3RfZGYkY3QxLCBsZXZlbHMgPSBsZXZlbHMocGxvdF9kZiRjdDEpW2hjbCRvcmRlcl0pCiAgI3Bsb3RfZGYkY3QyID0gZmFjdG9yKHBsb3RfZGYkY3QyLCBsZXZlbHMgPSBsZXZlbHMocGxvdF9kZiRjdDIpW2hjbCRvcmRlcl0pCiAgcGxvdF9kZiRjdDEgPSBmYWN0b3IocGxvdF9kZiRjdDEsIGxldmVscyA9IGxldmVscyhuZXRfbmFtZXNfYWxsJFZhcjEpKQogIHBsb3RfZGYkY3QyID0gZmFjdG9yKHBsb3RfZGYkY3QyLCBsZXZlbHMgPSBsZXZlbHMobmV0X25hbWVzX2FsbCRWYXIxKSkKICAjcGxvdF9kZiRjdDEgPSBmYWN0b3IocGxvdF9kZiRjdDEsIGxldmVscyA9IHJldihjKCJTdGVsbGF0ZSBjZWxscyIsICJMU0VDIiwgIkVuZG90aGVsaWFsIGNlbGxzXG4obm9uLUxTRUMpIiwKICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJLdXBmZmVyIGNlbGxzIiwgImNEQ3MiLCAiTWFjcm9waGFnZXMiLCAiQ2hvbGFuZ2lvY3l0ZXMiLAogICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBEQ3MiLCAiYWItVCBjZWxscyIsICJIZXBhdG9jeXRlcyIsICJnZC1UIGNlbGxzIiwgCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQiBjZWxscyIsICJQbGFzbWFibGFzdHMiKSkpCiAgI3Bsb3RfZGYkY3QyID0gZmFjdG9yKHBsb3RfZGYkY3QyLCBsZXZlbHMgPSByZXYoYygiU3RlbGxhdGUgY2VsbHMiLCAiTFNFQyIsICJFbmRvdGhlbGlhbCBjZWxsc1xuKG5vbi1MU0VDKSIsCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiS3VwZmZlciBjZWxscyIsICJjRENzIiwgIk1hY3JvcGhhZ2VzIiwgIkNob2xhbmdpb2N5dGVzIiwKICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwRENzIiwgImFiLVQgY2VsbHMiLCAiSGVwYXRvY3l0ZXMiLCAiZ2QtVCBjZWxscyIsIAogICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkIgY2VsbHMiLCAiUGxhc21hYmxhc3RzIikpKQogIHBsdGNudHMgPSBnZ3Bsb3QocGxvdF9kZltvcmRlcihwbG90X2RmJEZyZXEsIGRlY3JlYXNpbmcgPSBGKSxdLCAKICAgICAgICAgICAgICAgICAgIGFlcyh4ID0gY3QxLCB5ID0gY3QyLCBzaXplID0gYWJzKEZyZXEpLCBjb2xvdXIgPSBGcmVxKSkrCiAgICBnZW9tX3BvaW50KCkrCiAgICBsYWJzKHggPSAiY2VsbCB0eXBlIiwgeSA9ICJjZWxsIHR5cGUiLCB0aXRsZSA9IHBhc3RlMChuLCAiIC0gaGVhbHRoeSIpKSsKICAgIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9sZWdlbmQodGl0bGUgPSAiY2hhbmdlIGluXG4jIGludGVyYWN0aW9ucyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXZlcnNlID0gVCwgb3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gNCkpLCAKICAgICAgICAgICBzaXplID0gZ3VpZGVfbm9uZSgpKSsKICAgIHNjYWxlX2NvbG91cl9ncmFkaWVudG4oY29sb3JzID0gYygiI2Q3MTkxYyIsICIjZmRhZTYxIiwgIiNlZGVkZWQiLCAiI2MyYTVjZiIsICIjN2IzMjk0IiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICBsaW1pdHMgPSBjKC0xMTAsIDExMCkpKwogICAgc2NhbGVfc2l6ZV9jb250aW51b3VzKHJhbmdlID0gYygwLjIsIDUpKSsKICAgIHRoZW1lX2NsYXNzaWMoKSsKICAgIHRoZW1lKGFzcGVjdC5yYXRpbyA9IDEsCiAgICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJibGFjayIpLAogICAgICAgICAgYXhpcy5saW5lID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxLCB2anVzdCA9IDAuNCksCiAgICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoY29sb3VyID0gImJsYWNrIiwgc2l6ZSA9IDgpKQogIHByaW50KHBsdGNudHMpCiAgZGlmZl9jbnRfbFtbbl1dID0gcGx0Y250cwp9CmRpZmZfY250X2wkbGVnZW5kID0gY293cGxvdDo6Z2V0X2xlZ2VuZChkaWZmX2NudF9sJGVtYm9saXNlZCkKZGlmZl9jbnRfbCRlbWJvbGlzZWQgPSBkaWZmX2NudF9sJGVtYm9saXNlZCt0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCmRpZmZfY250X2wkcmVnZW5lcmF0aW5nID0gZGlmZl9jbnRfbCRyZWdlbmVyYXRpbmcrdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQoKcGRmKCJmaWd1cmVfcGFuZWxzX3JldjEvZmlnX2NvbW0vc3VwcEZpZ19jb3VudHNEaWZmLnBkZiIsIGhlaWdodCA9IDgsIHdpZHRoID0gMTUpCnByaW50KGNvd3Bsb3Q6OnBsb3RfZ3JpZChwbG90bGlzdCA9IGRpZmZfY250X2xbYygyLDEsMyldLCBuY29sID0gMywgcmVsX3dpZHRocyA9IGMoMSwxLDAuMyksIGFsaWduID0gImgiKSkKZGV2Lm9mZigpCmBgYAoKSGVhdG1hcHMgYnkgbWlkIGNlbGwgdHlwZQoKYGBge3J9Cm1hdGNoX2RmID0gdW5pcXVlKGRhdGEuZnJhbWUoImN0IiA9IGMocG9pbnRfY29uZF91bWFwX2RmJGN0LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTWlkem9uYWwgTFNFQyIsICJQZXJpY2VudHJhbCBMU0VDIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIklnRysgUGxhc21hIGNlbGxzIiwgIlRSTSBjZWxscyIsICJDRDggYWItVCBjZWxscyAzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiSGVwYXRvY3l0ZXNfWjEiLCJIZXBhdG9jeXRlc19aMiIsIkhlcGF0b2N5dGVzX1ozIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImN0X21pZCIgPSBjKHBvaW50X2NvbmRfdW1hcF9kZiRjdF9taWQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJMU0VDIiwgIkxTRUMiLCJCIGNlbGxzIiwgIlQgY2VsbHMiLCAiVCBjZWxscyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJIZXBhdG9jeXRlcyIsIkhlcGF0b2N5dGVzIiwiSGVwYXRvY3l0ZXMiKSkpCnJvd25hbWVzKG1hdGNoX2RmKSA9IG1hdGNoX2RmJGN0CgojIGhlYXRtYXBzIGJ5IG1pZCBjZWxsIHR5cGU/CmNudHNfbGlzdCA9IGxpc3QoKQp0YWJfbGlzdCA9IGxpc3QoKQpmb3IobiBpbiBuYW1lcyhpbnRlcl9kZilbMTozXSl7CiAgc3ViZGZjdCA9IHVuaXF1ZShpbnRlcl9kZltbbl1dWywxOjNdKQogIHN1YmRmY3QkY3QxW2dyZXBsKCJIZXBhdCIsIHN1YmRmY3QkY3QxKV0gPSAiSGVwYXRvY3l0ZXMiCiAgc3ViZGZjdCRjdDJbZ3JlcGwoIkhlcGF0Iiwgc3ViZGZjdCRjdDIpXSA9ICJIZXBhdG9jeXRlcyIKICBzdWJkZmN0JG1pZF9jdDEgPSBtYXRjaF9kZltzdWJkZmN0JGN0MSwgImN0X21pZCJdCiAgc3ViZGZjdCRtaWRfY3QyID0gbWF0Y2hfZGZbc3ViZGZjdCRjdDIsICJjdF9taWQiXQoKICBzdWJkZmN0ID0gdW5pcXVlKHN1YmRmY3RbLGMoMSw0OjUpXSkKICBkZmN0ID0gdGFibGUoZGF0YS5mcmFtZSgiY3QxIiA9IGMoc3ViZGZjdCRtaWRfY3QxLCBzdWJkZmN0JG1pZF9jdDIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICJjdDIiID0gYyhzdWJkZmN0JG1pZF9jdDIsIHN1YmRmY3QkbWlkX2N0MSkpKQogIGhjbCA9IGhjbHVzdChkaXN0KGRmY3QpLCBtZXRob2QgPSAid2FyZC5EMiIpCiAgcGxvdF9kZiA9IGRhdGEuZnJhbWUoZGZjdCkKICBwbG90X2RmJGN0MSA9IGZhY3RvcihwbG90X2RmJGN0MSwgbGV2ZWxzID0gaGNsJGxhYmVsc1toY2wkb3JkZXJdKQogIHBsb3RfZGYkY3QyID0gZmFjdG9yKHBsb3RfZGYkY3QyLCBsZXZlbHMgPSBoY2wkbGFiZWxzW2hjbCRvcmRlcl0pCiAgCiAgcGx0Y250cyA9IGdncGxvdChwbG90X2RmW29yZGVyKHBsb3RfZGYkRnJlcSwgZGVjcmVhc2luZyA9IEYpLF0sIAogICAgICAgICAgICAgICAgICAgYWVzKHggPSBjdDEsIHkgPSBjdDIsIHNpemUgPSBGcmVxLCBjb2xvdXIgPSBGcmVxKSkrCiAgICBnZW9tX3BvaW50KCkrCiAgICBsYWJzKHggPSAiY2VsbCB0eXBlIiwgeSA9ICJjZWxsIHR5cGUiLCB0aXRsZSA9IG4pKwogICAgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2xlZ2VuZCh0aXRsZSA9ICIjIGludGVyYWN0aW9ucyIsIHJldmVyc2UgPSBUKSwgCiAgICAgICAgICAgc2l6ZSA9IGd1aWRlX2xlZ2VuZCh0aXRsZSA9ICIjIGludGVyYWN0aW9ucyIsIHJldmVyc2UgPSBUKSkrCiAgICBzY2FsZV9jb2xvdXJfZ3JhZGllbnRuKGNvbG9ycyA9IGMoIiNlZGVkZWQiLCAiI2RlZWJmNyIsICIjOWVjYWUxIiwgIiNiY2JkZGMiLCAiIzc1NmJiMSIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYygwLCAzMjApKSsKICAgIHNjYWxlX3NpemVfY29udGludW91cyhsaW1pdHMgPSBjKDAsIDMyMCkpKwogICAgdGhlbWVfY2xhc3NpYygpKwogICAgdGhlbWUoYXNwZWN0LnJhdGlvID0gMSwKICAgICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImJsYWNrIiksCiAgICAgICAgICBheGlzLmxpbmUgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDEsIHZqdXN0ID0gMC40KSwKICAgICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChjb2xvdXIgPSAiYmxhY2siKSkKICBjbnRzX2xpc3RbW25dXSA9IHBsdGNudHMKICB0YWJfbGlzdFtbbl1dID0gZGZjdAp9CmNudHNfbGlzdCRsZWdlbmQgPSBjb3dwbG90OjpnZXRfbGVnZW5kKGNudHNfbGlzdCRoZWFsdGh5KQpjbnRzX2xpc3QkaGVhbHRoeSA9IGNudHNfbGlzdCRoZWFsdGh5K3RoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKY250c19saXN0JGVtYm9saXNlZCA9IGNudHNfbGlzdCRlbWJvbGlzZWQrdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQpjbnRzX2xpc3QkcmVnZW5lcmF0aW5nID0gY250c19saXN0JHJlZ2VuZXJhdGluZyt0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCgpwZGYoImZpZ3VyZV9wYW5lbHNfcmV2MS9maWdfY29tbS9zdXBwRmlnX2NvdW50c0NvbmRfbWlkLnBkZiIsIGhlaWdodCA9IDYuOSwgd2lkdGggPSA2LjkpCmNudHNfbGlzdFtbMV1dK2NudHNfbGlzdFtbM11dK2NudHNfbGlzdFtbMl1dK2NudHNfbGlzdFtbNF1dKyAgICAgIHBhdGNod29yazo6cGxvdF9sYXlvdXQobmNvbCA9IDIpCmRldi5vZmYoKQpgYGAKCmBgYHtyfQpkaWZmX2NudF9sID0gbGlzdCgpCmZvcihuIGluIGMoImVtYm9saXNlZCIsICJyZWdlbmVyYXRpbmciKSl7CiAgZGlmX2RmID0gdGFiX2xpc3RbW25dXS10YWJfbGlzdCRoZWFsdGh5CiAgaGNsID0gaGNsdXN0KGRpc3QoZGlmX2RmKSwgbWV0aG9kID0gIndhcmQuRDIiKQogIHBsb3RfZGYgPSBkYXRhLmZyYW1lKGRpZl9kZikKICBwbG90X2RmJGN0MSA9IGZhY3RvcihwbG90X2RmJGN0MSwgbGV2ZWxzID0gbGV2ZWxzKHBsb3RfZGYkY3QxKVtoY2wkb3JkZXJdKQogIHBsb3RfZGYkY3QyID0gZmFjdG9yKHBsb3RfZGYkY3QyLCBsZXZlbHMgPSBsZXZlbHMocGxvdF9kZiRjdDIpW2hjbCRvcmRlcl0pCgogIHBsdGNudHMgPSBnZ3Bsb3QocGxvdF9kZltvcmRlcihwbG90X2RmJEZyZXEsIGRlY3JlYXNpbmcgPSBGKSxdLCAKICAgICAgICAgICAgICAgICAgIGFlcyh4ID0gY3QxLCB5ID0gY3QyLCBzaXplID0gYWJzKEZyZXEpLCBjb2xvdXIgPSBGcmVxKSkrCiAgICBnZW9tX3BvaW50KCkrCiAgICBsYWJzKHggPSAiY2VsbCB0eXBlIiwgeSA9ICJjZWxsIHR5cGUiLCB0aXRsZSA9IHBhc3RlMChuLCAiIC0gaGVhbHRoeSIpKSsKICAgIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9sZWdlbmQodGl0bGUgPSAiY2hhbmdlIGluXG4jIGludGVyYWN0aW9ucyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXZlcnNlID0gVCwgb3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gNCkpLCAKICAgICAgICAgICBzaXplID0gZ3VpZGVfbm9uZSgpKSsKICAgIHNjYWxlX2NvbG91cl9ncmFkaWVudG4oY29sb3JzID0gYygiI2Q3MTkxYyIsICIjZmRhZTYxIiwgIiNlZGVkZWQiLCAiI2MyYTVjZiIsICIjN2IzMjk0IiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICBsaW1pdHMgPSBjKC0xNTAsIDE1MCkpKwogICAgc2NhbGVfc2l6ZV9jb250aW51b3VzKHJhbmdlID0gYygwLjIsIDUpKSsKICAgIHRoZW1lX2NsYXNzaWMoKSsKICAgIHRoZW1lKGFzcGVjdC5yYXRpbyA9IDEsCiAgICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJibGFjayIpLAogICAgICAgICAgYXhpcy5saW5lID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxLCB2anVzdCA9IDAuNCksCiAgICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoY29sb3VyID0gImJsYWNrIiwgc2l6ZSA9IDgpKQogIHByaW50KHBsdGNudHMpCiAgZGlmZl9jbnRfbFtbbl1dID0gcGx0Y250cwp9CmRpZmZfY250X2wkbGVnZW5kID0gY293cGxvdDo6Z2V0X2xlZ2VuZChkaWZmX2NudF9sJGVtYm9saXNlZCkKZGlmZl9jbnRfbCRlbWJvbGlzZWQgPSBkaWZmX2NudF9sJGVtYm9saXNlZCt0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCmRpZmZfY250X2wkcmVnZW5lcmF0aW5nID0gZGlmZl9jbnRfbCRyZWdlbmVyYXRpbmcrdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQoKcGRmKCJmaWd1cmVfcGFuZWxzX3JldjEvZmlnX2NvbW0vc3VwcEZpZ19jb3VudHNEaWZmX21pZC5wZGYiLCBoZWlnaHQgPSAzLjQ1LCB3aWR0aCA9IDYuOSkKcHJpbnQoY293cGxvdDo6cGxvdF9ncmlkKHBsb3RsaXN0ID0gZGlmZl9jbnRfbFtjKDIsMSwzKV0sIAogICAgICAgICAgICAgICAgICAgICAgICAgbmNvbCA9IDMsIHJlbF93aWR0aHMgPSBjKDEsMSwwLjMpLCBhbGlnbiA9ICJodiIpKQpkZXYub2ZmKCkKYGBgCgpVbmlxdWUgaW50ZXJhY3Rpb25zIGZyb20gRSBhbmQgUgoKYGBge3J9CiMgbnVtYmVyIG9mIG5ldyB1bmlxdWUgaW50ZXJhY3Rpb25zCiMjIGkuZS4gdGhpcyBsaWdhbmQtcmVjZXB0b3IgcGFpciB3YXMgYWJzZW50IGF0IGxlYXN0IGluIGhlYWx0aHkgYW5kIGFsd2F5cyBpbmNsdWRlcyB0aGlzIGN0CiMgZ2V0IGludGVyYWN0aW9ucyB0aGF0IGFyZSBub3QgaW4gaGVhbHRoeQppbnRlcl9oID0gaW50ZXJfZGYkaGVhbHRoeSRpZF9jcF9pbnRlcmFjdGlvbgppbnRlcl9yZWdfc3ViID0gaW50ZXJfZGYkcmVnZW5lcmF0aW5nWyFpbnRlcl9kZiRyZWdlbmVyYXRpbmckaWRfY3BfaW50ZXJhY3Rpb24gJWluJSBpbnRlcl9oLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDE6M10KaW50ZXJfZW1iX3N1YiA9IGludGVyX2RmJGVtYm9saXNlZFshaW50ZXJfZGYkZW1ib2xpc2VkJGlkX2NwX2ludGVyYWN0aW9uICVpbiUgaW50ZXJfaCwgMTozXQoKcHZlX2ludGVyID0gcmJpbmQoaW50ZXJfcmVnX3N1YiwgaW50ZXJfZW1iX3N1YikKcHZlX2ludGVyJGNvbmQgPSBjKHJlcCgicmVnZW5lcmF0aW5nIiwgbnJvdyhpbnRlcl9yZWdfc3ViKSksCiAgICAgICAgICAgICAgICAgICByZXAoImVtYm9saXNlZCIsIG5yb3coaW50ZXJfZW1iX3N1YikpKQpwdmVfaW50ZXIkbWlkX2N0MSA9IG1hdGNoX2RmW3B2ZV9pbnRlciRjdDEsImN0X21pZCJdCnB2ZV9pbnRlciRtaWRfY3QyID0gbWF0Y2hfZGZbcHZlX2ludGVyJGN0MiwiY3RfbWlkIl0KCiMgbGlzdCB1bmlxdWUgaW50ZXJhY3Rpb25zIChhbGwgY3QpCmN0X2ludGVyX2wgPSBsaXN0KCkKZm9yKGNvbmQgaW4gdW5pcXVlKHB2ZV9pbnRlciRjb25kKSl7CiAgY3RfaW50ZXJfbFtbY29uZF1dID0gbGlzdCgpCiAgc3ViX3B2ZV9pbnRlciA9IHB2ZV9pbnRlcltwdmVfaW50ZXIkY29uZD09Y29uZCxdCiAgc3ViX3B2ZV9pbnRlciA9IHN1Yl9wdmVfaW50ZXJbc3ViX3B2ZV9pbnRlciRjdDEhPXN1Yl9wdmVfaW50ZXIkY3QyLF0KICAKICBpbnRlcl91ID0gdW5pcXVlKHN1Yl9wdmVfaW50ZXIkaWRfY3BfaW50ZXJhY3Rpb24pCiAgZm9yKGkgaW4gaW50ZXJfdSl7CiAgICBpZGYgPSBzdWJfcHZlX2ludGVyW3N1Yl9wdmVfaW50ZXIkaWRfY3BfaW50ZXJhY3Rpb249PWksIGMoImN0MSIsICJjdDIiKV0KICAgIHRhYl9pbnRfbnUgPSB0YWJsZShpZGYkY3QxLCBpZGYkY3QyKQogICAgCiAgICBpZihucm93KHRhYl9pbnRfbnUpPT0xKXsKICAgICAgY3RfaW50ZXJfbFtbY29uZF1dW1tpXV0gPSByb3duYW1lcyh0YWJfaW50X251KQogICAgfQogICAgaWYobmNvbCh0YWJfaW50X251KT09MSl7CiAgICAgIGN0X2ludGVyX2xbW2NvbmRdXVtbaV1dID0gY29sbmFtZXModGFiX2ludF9udSkKICAgIH0KICB9CiAgCn0KY3RfaW50ZXJfbCA9IHJlc2hhcGUyOjptZWx0KGN0X2ludGVyX2wpCnRhYmxlKGN0X2ludGVyX2wkdmFsdWUsIGN0X2ludGVyX2wkTDEpCgojIGxpc3QgdW5pcXVlIGludGVyYWN0aW9ucyAobWlkIGN0KQpjdG1pZF9pbnRlcl9sID0gbGlzdCgpCmN0bWlkX2ludGVyX2xfY3QgPSBsaXN0KCkKZm9yKGNvbmQgaW4gdW5pcXVlKHB2ZV9pbnRlciRjb25kKSl7CiAgY3RtaWRfaW50ZXJfbFtbY29uZF1dID0gbGlzdCgpCiAgY3RtaWRfaW50ZXJfbF9jdFtbY29uZF1dID0gbGlzdCgpCiAgc3ViX3B2ZV9pbnRlciA9IHB2ZV9pbnRlcltwdmVfaW50ZXIkY29uZD09Y29uZCxdCiAgc3ViX3B2ZV9pbnRlciA9IHN1Yl9wdmVfaW50ZXJbc3ViX3B2ZV9pbnRlciRtaWRfY3QxIT1zdWJfcHZlX2ludGVyJG1pZF9jdDIsXQogIAogIGludGVyX3UgPSB1bmlxdWUoc3ViX3B2ZV9pbnRlciRpZF9jcF9pbnRlcmFjdGlvbikKICBmb3IoaSBpbiBpbnRlcl91KXsKICAgIGlkZiA9IHN1Yl9wdmVfaW50ZXJbc3ViX3B2ZV9pbnRlciRpZF9jcF9pbnRlcmFjdGlvbj09aSwgYygibWlkX2N0MSIsICJtaWRfY3QyIildCiAgICB0YWJfaW50X251ID0gdGFibGUoaWRmJG1pZF9jdDEsIGlkZiRtaWRfY3QyKQogICAgbWlkX2N0MV9jdCA9IHN1Yl9wdmVfaW50ZXJbc3ViX3B2ZV9pbnRlciRpZF9jcF9pbnRlcmFjdGlvbj09aSwgImN0MSJdCiAgICBtaWRfY3QyX2N0ID0gc3ViX3B2ZV9pbnRlcltzdWJfcHZlX2ludGVyJGlkX2NwX2ludGVyYWN0aW9uPT1pLCAiY3QyIl0KICAgIAogICAgaWYobnJvdyh0YWJfaW50X251KT09MSl7CiAgICAgIGN0bWlkX2ludGVyX2xbW2NvbmRdXVtbaV1dID0gcm93bmFtZXModGFiX2ludF9udSkKICAgICAgY3RtaWRfaW50ZXJfbF9jdFtbY29uZF1dW1tpXV0gPSBtaWRfY3QxX2N0CiAgICB9CiAgICBpZihuY29sKHRhYl9pbnRfbnUpPT0xKXsKICAgICAgY3RtaWRfaW50ZXJfbFtbY29uZF1dW1tpXV0gPSBjb2xuYW1lcyh0YWJfaW50X251KQogICAgICBjdG1pZF9pbnRlcl9sX2N0W1tjb25kXV1bW2ldXSA9IG1pZF9jdDJfY3QKICAgIH0KICB9CiAgCn0KY3RtaWRfaW50ZXJfbCA9IHJlc2hhcGUyOjptZWx0KGN0bWlkX2ludGVyX2wpCmN0bWlkX2ludGVyX2xfY3QgPSB1bmlxdWUocmVzaGFwZTI6Om1lbHQoY3RtaWRfaW50ZXJfbF9jdCkpCmN0bWlkX2ludGVyX2wgPSBtZXJnZShjdG1pZF9pbnRlcl9sLCBjdG1pZF9pbnRlcl9sX2N0LCBieSA9IGMoIkwyIiwgIkwxIiksIAogICAgICAgICAgICAgICAgICAgICAgYWxsID0gVClbLGMoMywxLDIsNCldCnRhYmxlKGN0bWlkX2ludGVyX2wkdmFsdWUueCwgY3RtaWRfaW50ZXJfbCRMMSkKYGBgCgpGdW5jdGlvbnMgdG8gcGxvdCBpbnRlcmFjdGlvbnMKCmBgYHtyfQpmaWx0RnVuY1UgPSBmdW5jdGlvbih4LCBpbnRkZiwgbXV0dGhyID0gMCwgZXhwdGhyID0gMC4xMiwgbWluY3QgPSAzKXsKICBjb2xkZiA9IHhbLDE6OF0KICAjaW50X2N0X3BfdCA9IHBhc3RlMChpbnRkZiR2YWx1ZSwgaW50ZGYkTDIpCiAgY29sZGYkaXNNYWluMSA9IGFwcGx5KGNvbGRmLCAxLCBmdW5jdGlvbih5KSBwYXN0ZTAoeVsyXSwgeVsxXSkgJWluJSBpbnRkZikKICBjb2xkZiRpc01haW4yID0gYXBwbHkoY29sZGYsIDEsIGZ1bmN0aW9uKHkpIHBhc3RlMCh5WzNdLCB5WzFdKSAlaW4lIGludGRmKQogIAogICMgc3dhcCBpZiBpc01haW4yCiAgZm9yKGkgaW4gMTpucm93KGNvbGRmKSl7CiAgICBpZihjb2xkZltpLCJpc01haW4yIl0pewogICAgICB0bXBjdCA9IGNvbGRmW2ksImN0MiJdCiAgICAgIHRtcGxyID0gY29sZGZbaSwibHIyIl0KICAgICAgdG1wbWEgPSBjb2xkZltpLCJpc01haW4yIl0KICAgICAgCiAgICAgIGNvbGRmW2ksImN0MiJdID0gY29sZGZbaSwiY3QxIl0KICAgICAgY29sZGZbaSwibHIyIl0gPSBjb2xkZltpLCJscjEiXQogICAgICBjb2xkZltpLCJpc01haW4yIl0gPSBjb2xkZltpLCJpc01haW4xIl0KICAgICAgCiAgICAgIGNvbGRmW2ksImN0MSJdID0gdG1wY3QKICAgICAgY29sZGZbaSwibHIxIl0gPSB0bXBscgogICAgICBjb2xkZltpLCJpc01haW4xIl0gPSB0bXBtYQogICAgfQogIH0KCiAgIyBpbnRlcmFjdGlvbiBuYW1lcwogIGNvbGRmJGludGxyID0gcGFzdGUwKGNvbGRmJGxyMSwgIiAtXG4gIiwgY29sZGYkbHIyKQogIGNvbGRmID0gdW5pcXVlKGNvbGRmWyxjKDIsMywxMSw2OjEwKV0pCiAgIyBpbnRlcmFjdGlvbiBmcmVxdWVuY3kKICBuaW50ID0gdGFibGUoY29sZGYkaW50bHIpCiAgIyBleHByZXNzaW9uIGFuZCBpbnRlcmFjdGlvbiBmaWx0ZXJpbmcKICBjb2xkZiA9IGNvbGRmW2FwcGx5KGNvbGRmWyw0OjZdLCAxLCBmdW5jdGlvbih4KSBhbnkoeD49ZXhwdGhyKSkgJiAKICAgICAgICAgICAgICAgICAgKGNvbGRmJGludGxyICVpbiUgbmFtZXMobmludClbbmludD4xXSB8IAogICAgICAgICAgICAgICAgICAgICBhcHBseShjb2xkZlssNDo2XSwgMSwgZnVuY3Rpb24oeCkgYW55KHg+PWV4cHRocio4KSkpLF0KICAjIHJlc2hhcGluZyBmb3IgcGxvdAogIGNvbGRmID0gZGF0YS50YWJsZTo6cmJpbmRsaXN0KGxpc3QocmVzaGFwZTI6Om1lbHQoY29sZGZbLGMoMywxLDQ6NyldKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXNoYXBlMjo6bWVsdChjb2xkZlssYygzLDIsNDo2LCA4KV0pKSwgdXNlLm5hbWVzID0gRikKICBjb2xkZiR2YXJpYWJsZSA9IHVubGlzdChsYXBwbHkoc3Ryc3BsaXQoYXMuY2hhcmFjdGVyKGNvbGRmJHZhcmlhYmxlKSwgIl8iKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uKHgpIHhbMV0pKQogIGNvbGRmJHZhcmlhYmxlID0gZmFjdG9yKGNvbGRmJHZhcmlhYmxlLCBsZXZlbHMgPSBjKCJoZWFsdGh5IiwicmVnZW5lcmF0aW5nIiwgImVtYm9saXNlZCIpKQogIGNvbGRmID0gY29sZGZbb3JkZXIoY29sZGYkdmFsdWUsIGRlY3JlYXNpbmcgPSBUKSxdCiAgY29sZGYgPSBjb2xkZlshZHVwbGljYXRlZChjb2xkZlssMTo0XSksXQogIGNvbGRmJGN0MSA9IGdzdWIoIkVuZG90aGVsaWFsIGNlbGxzIiwgIkVDIiwgY29sZGYkY3QxKQogIGNvbGRmJGludGxyID0gZ3N1YigicmVjZXB0b3IiLCAicmVjIiwgY29sZGYkaW50bHIpCiAgY29sZGYkaW50bHIgPSBnc3ViKCJjb21wbGV4IiwgImNvbXAiLCBjb2xkZiRpbnRscikKICBuY3QgPSB0YWJsZShjb2xkZiRjdDEpCiAgY29sZGYgPSBjb2xkZltjb2xkZiRjdDEgJWluJSBuYW1lcyhuY3QpW25jdD49bWluY3QqM10sXQogIG5pbnQgPSB0YWJsZShjb2xkZiRpbnRscikKICBjb2xkZiA9IGNvbGRmW2NvbGRmJGludGxyICVpbiUgbmFtZXMobmludClbbmludD4zXSxdCiAgCiAgIyBjb25maXJtIHRoYXQgYWxsIGludGVyYWN0aW9ucyBoYXZlIGF0IGxlYXN0IG9uZSBUUlVFCiAgbnRydWUgPSB0YXBwbHkoY29sZGYkaXNNYWluMSwgY29sZGYkaW50bHIsIHN1bSkKICBjb2xkZiA9IGNvbGRmW2NvbGRmJGludGxyICVpbiUgbmFtZXMobnRydWUpW250cnVlPjBdXQogIAogICMgZm9ybWF0dGluZwogIGNvbGRmID0gY29sZGZbb3JkZXIoY29sZGYkaXNNYWluMSwgY29sZGYkaW50bHIsIC1jb2xkZiR2YWx1ZSwgZGVjcmVhc2luZyA9IFQpLF0KICBjb2xkZiRjdDEgPSBmYWN0b3IoY29sZGYkY3QxLCBsZXZlbHMgPSByZXYodW5pcXVlKGNvbGRmJGN0MSkpKQogIGNvbGRmJGludGxyID0gZmFjdG9yKGNvbGRmJGludGxyLCBsZXZlbHMgPSByZXYodW5pcXVlKGNvbGRmJGludGxyKSkpCiAgY29sZGYgPSBjb2xkZltvcmRlcihjb2xkZiRpc01haW4xLCBkZWNyZWFzaW5nID0gRiksXQogIAogIHJldHVybihjb2xkZikKfQoKcGx0RnVuY1UgPSBmdW5jdGlvbih4KXsKICBwbHQgPSBnZ3Bsb3QoeCwgYWVzKHkgPSBjdDEsIHggPSB2YXJpYWJsZSwgZmlsbCA9IHZhbHVlLCBjb2xvdXIgPSBpc01haW4xKSkrCiAgICBmYWNldF9ncmlkKGludGxyfi4sIHNjYWxlcyA9ICJmcmVlX3kiLCBzcGFjZSA9ICJmcmVlX3kiKSsKICAgIGdlb21fdGlsZShzaXplID0gMC40KSsKICAgIHNjYWxlX3hfZGlzY3JldGUoZXhwYW5kID0gYygwLDApKSsKICAgIHNjYWxlX2ZpbGxfZ3JhZGllbnRuKGNvbG9ycyA9IGdyYWRleHBjb2wpKwogICAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCJ3aGl0ZSIsICJibGFjayIpKSsKICAgIGd1aWRlcyhmaWxsID0gZ3VpZGVfY29sb3VyYmFyKGJhcmhlaWdodCA9IHVuaXQoMC40LCAiY20iKSksCiAgICAgICAgICAgY29sb3VyID0gZ3VpZGVfbm9uZSgpKSsKICAgIGxhYnMoeCA9ICJDb25kaXRpb24iLCB5ID0gIkNlbGwgdHlwZSIsIGZpbGwgPSAibWVhbiBleHAiKSsKICAgIHRoZW1lX2NsYXNzaWMoKSsKICAgIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KGNvbG91ciA9ICJibGFjayIsIHNpemUgPSA3LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFuZ2xlID0gMCwgaGp1c3QgPSAxLCB2anVzdCA9IDAuNSksCiAgICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChjb2xvdXIgPSAiYmxhY2siLCBzaXplID0gNi41LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFuZ2xlID0gMzUsIGhqdXN0PTEsIHZqdXN0PTEpLAogICAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gNyksCiAgICAgICAgICBheGlzLmxpbmUgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwKICAgICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gNyksCiAgICAgICAgICBsZWdlbmQuYm94Lm1hcmdpbiA9IG1hcmdpbigwLDAsMCwwKSwKICAgICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA2KSwKICAgICAgICAgIHN0cmlwLnRleHQueSA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDAsIHNpemUgPSA3LCBtYXJnaW4gPSBtYXJnaW4oMCwwLDMsMCksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhqdXN0ID0gMC41LCB2anVzdCA9IDAuNSwgZmFjZSA9ICJib2xkIiksCiAgICAgICAgICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpKQogIHJldHVybihwbHQpCn0KYGBgCgpQbG90IGFsbAoKYGBge3J9CnBsb3RfZGYgPSBmaWx0RnVuY1UoaGVyX2FsbGludF9mW2hlcl9hbGxpbnRfZiRpZF9jcF9pbnRlcmFjdGlvbiAlaW4lIGN0X2ludGVyX2wkTDJbIWdyZXBsKCJzdHJlc3MiLCBjdF9pbnRlcl9sJHZhbHVlKV0sXSwKICAgICAgICAgICAgICAgICAgICBpbnRkZiA9IHBhc3RlMChjdF9pbnRlcl9sJHZhbHVlLCBjdF9pbnRlcl9sJEwyKSwgCiAgICAgICAgICAgICAgICAgICAgZXhwdGhyID0gMC4yLCBtaW5jdCA9IDEpCmltbV9wbHQgPSBwbHRGdW5jVShwbG90X2RmKQpwZGYoImZpZ3VyZV9wYW5lbHNfcmV2MS9maWdfY29tbS9tYWluRmlnX0ludGVyYWN0VW5pcXVlLnBkZiIsIAogICAgaGVpZ2h0ID0gMjAsIHdpZHRoID0gMi44KQpwcmludChpbW1fcGx0KQpkZXYub2ZmKCkKCnBsb3RfZGYgPSBmaWx0RnVuY1UoaGVyX2FsbGludF9mW2hlcl9hbGxpbnRfZiRpZF9jcF9pbnRlcmFjdGlvbiAlaW4lIGN0bWlkX2ludGVyX2wkTDJbIWdyZXBsKCJzdHJlc3MiLCBjdG1pZF9pbnRlcl9sJHZhbHVlLnkpXSxdLAogICAgICAgICAgICAgICAgICAgaW50ZGYgPSBwYXN0ZTAoY3RtaWRfaW50ZXJfbCR2YWx1ZS55LCBjdG1pZF9pbnRlcl9sJEwyKSwgCiAgICAgICAgICAgICAgICAgICBleHB0aHIgPSAwLjIsIG1pbmN0ID0gMykKaW1tX3BsdCA9IHBsdEZ1bmNVKHBsb3RfZGYpCnBkZigiZmlndXJlX3BhbmVsc19yZXYxL2ZpZ19jb21tL21haW5GaWdfSW50ZXJhY3RVbmlxdWVfbWlkLnBkZiIsIAogICAgaGVpZ2h0ID0gMzIsIHdpZHRoID0gMi44KQpwcmludChpbW1fcGx0KQpkZXYub2ZmKCkKYGBgCgpQbG90IG9uZSBieSBvbmUKCmBgYHtyfQpwbG90X2RmID0gZmlsdEZ1bmNVKGhlcl9hbGxpbnRfZltoZXJfYWxsaW50X2YkaWRfY3BfaW50ZXJhY3Rpb24gJWluJSBjdF9pbnRlcl9sJEwyWyFncmVwbCgic3RyZXNzIiwgY3RfaW50ZXJfbCR2YWx1ZSldLF0sCiAgICAgICAgICAgICAgICAgICAgaW50ZGYgPSBwYXN0ZTAoY3RfaW50ZXJfbCR2YWx1ZSwgY3RfaW50ZXJfbCRMMiksIAogICAgICAgICAgICAgICAgICAgIGV4cHRociA9IDAuMiwgbWluY3QgPSAzKQoKZm9sZGVyID0gImZpZ3VyZV9wYW5lbHNfcmV2MS9maWdfY29tbS9oZWF0bWFwc19pbnRlcmFjdF9pbmRpdi8iCmZvcihpIGluIDE6bGVuZ3RoKHVuaXF1ZShwbG90X2RmJGludGxyKSkpewogIGlpaSA9IHVuaXF1ZShwbG90X2RmJGludGxyKVtpXQogIHN1Yl9wbG90X2RmID0gcGxvdF9kZltwbG90X2RmJGludGxyPT1paWksXQogIHN1Yl9wbG90X2RmID0gc3ViX3Bsb3RfZGZbb3JkZXIoc3ViX3Bsb3RfZGYkaXNNYWluMSwgc3ViX3Bsb3RfZGYkdmFsdWUsIGRlY3JlYXNpbmcgPSBUKSxdCiAgc3ViX3Bsb3RfZGYkY3QxID0gZmFjdG9yKHN1Yl9wbG90X2RmJGN0MSwgbGV2ZWxzID0gcmV2KHVuaXF1ZShzdWJfcGxvdF9kZiRjdDEpKSkKICBzdWJfcGxvdF9kZiA9IHN1Yl9wbG90X2RmW29yZGVyKHN1Yl9wbG90X2RmJGlzTWFpbjEsIGRlY3JlYXNpbmcgPSBGKSxdCiAgCiAgcGRmKHBhc3RlMChmb2xkZXIsICJtYWluRmlnX0ludGVyYWN0VW5pcXVlXyIsIGksICIucGRmIiksIGhlaWdodCA9IDMsIHdpZHRoID0gNCkKICBwcmludChwbHRGdW5jVShzdWJfcGxvdF9kZikpCiAgZGV2Lm9mZigpCn0KCnBsb3RfZGYgPSBmaWx0RnVuY1UoaGVyX2FsbGludF9mW2hlcl9hbGxpbnRfZiRpZF9jcF9pbnRlcmFjdGlvbiAlaW4lIGN0bWlkX2ludGVyX2wkTDJbIWdyZXBsKCJzdHJlc3MiLCBjdG1pZF9pbnRlcl9sJHZhbHVlLnkpXSxdLAogICAgICAgICAgICAgICAgICAgaW50ZGYgPSBwYXN0ZTAoY3RtaWRfaW50ZXJfbCR2YWx1ZS55LCBjdG1pZF9pbnRlcl9sJEwyKSwgCiAgICAgICAgICAgICAgICAgICBleHB0aHIgPSAwLjIsIG1pbmN0ID0gMykKCmZvbGRlciA9ICJmaWd1cmVfcGFuZWxzX3JldjEvZmlnX2NvbW0vaGVhdG1hcHNfaW50ZXJhY3RfaW5kaXYvIgpmb3IoaSBpbiAxOmxlbmd0aCh1bmlxdWUocGxvdF9kZiRpbnRscikpKXsKICBpaWkgPSB1bmlxdWUocGxvdF9kZiRpbnRscilbaV0KICBzdWJfcGxvdF9kZiA9IHBsb3RfZGZbcGxvdF9kZiRpbnRscj09aWlpLF0KICBzdWJfcGxvdF9kZiA9IHN1Yl9wbG90X2RmW29yZGVyKHN1Yl9wbG90X2RmJGlzTWFpbjEsIHN1Yl9wbG90X2RmJHZhbHVlLCBkZWNyZWFzaW5nID0gVCksXQogIHN1Yl9wbG90X2RmJGN0MSA9IGZhY3RvcihzdWJfcGxvdF9kZiRjdDEsIGxldmVscyA9IHJldih1bmlxdWUoc3ViX3Bsb3RfZGYkY3QxKSkpCiAgc3ViX3Bsb3RfZGYgPSBzdWJfcGxvdF9kZltvcmRlcihzdWJfcGxvdF9kZiRpc01haW4xLCBkZWNyZWFzaW5nID0gRiksXQogIAogIHBkZihwYXN0ZTAoZm9sZGVyLCAibWFpbkZpZ19JbnRlcmFjdFVuaXF1ZV9taWRfIiwgaSwgIi5wZGYiKSwgaGVpZ2h0ID0gMywgd2lkdGggPSAyLjgpCiAgcHJpbnQocGx0RnVuY1Uoc3ViX3Bsb3RfZGYpKQogIGRldi5vZmYoKQp9CmBgYAoKUGxvdCBvbmUgYnkgb25lLCBhbGwgaW4gSCB2cyBQVkUgbmV0d29yawoKYGBge3J9CmVkZ2VfbWluID0gZWRnZV9jb25kX2RmWyxjKDE6NCw5OjEyKV0KZWRnZV9taW4gPSBtZXJnZShlZGdlX21pbiwgdW5pcXVlKGhlcl9hbGxpbnRfZlssYygxLDEzKV0pLCBieS54ID0gMywgYnkueSA9IDEsIGFsbC54ID0gVCkKZWRnZV9taW4gPSBtZXJnZShlZGdlX21pbiwgdW5pcXVlKGhlcl9hbGxpbnRfZlssYygxLDE3KV0pLCBieS54ID0gMSwgYnkueSA9IDEsIGFsbC54ID0gVCkKZWRnZV9taW4gPSBlZGdlX21pbltlZGdlX21pbiRjdF9nMSE9ZWRnZV9taW4kY3RfZzIsXQplZGdlX21pbiA9IGVkZ2VfbWluW2VkZ2VfbWluJGlkX2NwX2ludGVyYWN0aW9uICVpbiUgY29tcGhfaW50ZXJzLF0KCnBsb3RfZGYgPSBmaWx0RnVuYyhoZXJfYWxsaW50X2ZbaGVyX2FsbGludF9mJGlkX2NwX2ludGVyYWN0aW9uICVpbiUgdW5pcXVlKGVkZ2VfbWluJGlkX2NwX2ludGVyYWN0aW9uKSxdLAogICAgICAgICAgICAgICAgICAgZXhwdGhyID0gMC4xNSwgbWluY3QgPSAyKQojaW1tX3BsdCA9IHBsdEZ1bmMocGxvdF9kZikKI3BkZigiZmlndXJlX3BhbmVsc19yZXYxL2ZpZ19jb21tL3Rlc3QucGRmIiwgd2lkdGggPSA1MCwgaGVpZ2h0ID0gMykKI3ByaW50KGltbV9wbHQpCiNkZXYub2ZmKCkKCmZvbGRlciA9ICJmaWd1cmVfcGFuZWxzX3JldjEvZmlnX2NvbW0vaGVhdG1hcHNfaW50ZXJhY3RfaW5kaXZfaHB2ZS8iCmZvcihpIGluIDE6bGVuZ3RoKHVuaXF1ZShwbG90X2RmJGludGxyKSkpewogIGlpaSA9IHVuaXF1ZShwbG90X2RmJGludGxyKVtpXQogIHN1Yl9wbG90X2RmID0gcGxvdF9kZltwbG90X2RmJGludGxyPT1paWksXQogIHN1Yl9wbG90X2RmID0gc3ViX3Bsb3RfZGZbb3JkZXIoc3ViX3Bsb3RfZGYkdmFsdWUsIGRlY3JlYXNpbmcgPSBUKSxdCiAgc3ViX3Bsb3RfZGYkY3QxID0gZmFjdG9yKHN1Yl9wbG90X2RmJGN0MSwgbGV2ZWxzID0gcmV2KHVuaXF1ZShzdWJfcGxvdF9kZiRjdDEpKSkKCiAgcGRmKHBhc3RlMChmb2xkZXIsICJtYWluRmlnX0ludGVyYWN0SFBWRV8iLCBpLCAiLnBkZiIpLCBoZWlnaHQgPSAzLCB3aWR0aCA9IDQpCiAgcHJpbnQocGx0RnVuYyhzdWJfcGxvdF9kZikpCiAgZGV2Lm9mZigpCn0KYGBgCgpQbG90IGNoYW5nZXMgaW4gbnVtYmVyIG9mIGludGVyYWN0aW9ucyBwZXIgY29uZGl0aW9uIC0gbWlkIHJlc29sdXRpb24KCmBgYHtyfQptYXRjaF9kZiA9IHVuaXF1ZShkYXRhLmZyYW1lKCJjdCIgPSBjKHBvaW50X2NvbmRfdW1hcF9kZiRjdCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk1pZHpvbmFsIExTRUMiLCAiUGVyaWNlbnRyYWwgTFNFQyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJJZ0crIFBsYXNtYSBjZWxscyIsICJUUk0gY2VsbHMiLCAiQ0Q4IGFiLVQgY2VsbHMgMyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkhlcGF0b2N5dGVzX1oxIiwiSGVwYXRvY3l0ZXNfWjIiLCJIZXBhdG9jeXRlc19aMyIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjdF9taWQiID0gYyhwb2ludF9jb25kX3VtYXBfZGYkY3RfbWlkLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTFNFQyIsICJMU0VDIiwiQiBjZWxscyIsICJUIGNlbGxzIiwgIlQgY2VsbHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiSGVwYXRvY3l0ZXMiLCJIZXBhdG9jeXRlcyIsIkhlcGF0b2N5dGVzIikpKQpyb3duYW1lcyhtYXRjaF9kZikgPSBtYXRjaF9kZiRjdAoKIyBjb3JyZWN0IHNvbWUgbmFtZXMKcmVmb3JtX2xpc3RfaW50ID0gbGlzdCgpCmZvcihuIGluIG5hbWVzKHJlZm9ybV9saXN0KVsxOjNdKXsKICByZWZvcm1fbGlzdFtbbl1dJGN0MVtncmVwbCgiSGVwYSIsIHJlZm9ybV9saXN0W1tuXV0kY3QxKV0gPSAiSGVwYXRvY3l0ZXMiCiAgcmVmb3JtX2xpc3RbW25dXSRjdDJbZ3JlcGwoIkhlcGEiLCByZWZvcm1fbGlzdFtbbl1dJGN0MildID0gIkhlcGF0b2N5dGVzIgogIHJlZm9ybV9saXN0W1tuXV0kY3QxW2dyZXBsKCJMU0VDXyIsIHJlZm9ybV9saXN0W1tuXV0kY3QxKV0gPSAiTFNFQyIKICByZWZvcm1fbGlzdFtbbl1dJGN0MltncmVwbCgiTFNFQ18iLCByZWZvcm1fbGlzdFtbbl1dJGN0MildID0gIkxTRUMiCiAgcmVmb3JtX2xpc3RfaW50W1tuXV0gPSByZWZvcm1fbGlzdFtbbl1dW3JlZm9ybV9saXN0W1tuXV0kY3QxIT0iRGl2aWRpbmcgY2VsbHMiICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWZvcm1fbGlzdFtbbl1dJGN0MiE9IkRpdmlkaW5nIGNlbGxzIixdCiAgcmVmb3JtX2xpc3RfaW50W1tuXV0gPSByZWZvcm1fbGlzdF9pbnRbW25dXVshZHVwbGljYXRlZChyZWZvcm1fbGlzdF9pbnRbW25dXVssMTozXSksMTozXQogIAogIHJlZm9ybV9saXN0X2ludFtbbl1dJG1pZF9jdDEgPSBtYXRjaF9kZltyZWZvcm1fbGlzdF9pbnRbW25dXSRjdDEsImN0X21pZCJdCiAgcmVmb3JtX2xpc3RfaW50W1tuXV0kbWlkX2N0MiA9IG1hdGNoX2RmW3JlZm9ybV9saXN0X2ludFtbbl1dJGN0MiwiY3RfbWlkIl0KICAKICByZWZvcm1fbGlzdF9pbnRbW25dXSA9IHVuaXF1ZShyZWZvcm1fbGlzdF9pbnRbW25dXVssYygxLDQ6NSldKQogIGNvbG5hbWVzKHJlZm9ybV9saXN0X2ludFtbbl1dKVsyOjNdID0gYygiY3QxIiwgImN0MiIpCn0KCiMgY291bnQgaW50ZXJhY3Rpb25zCmluZmVyX2RmID0gZGF0YS5mcmFtZShleHBhbmQuZ3JpZCh1bmlxdWUocmVmb3JtX2xpc3RfaW50JGhlYWx0aHkkY3QxKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1bmlxdWUocmVmb3JtX2xpc3RfaW50JGhlYWx0aHkkY3QxKSkpCm5yID0gbnJvdyhpbmZlcl9kZikKaW5mZXJfZGYgPSByYmluZChpbmZlcl9kZiwgaW5mZXJfZGYsIGluZmVyX2RmKQppbmZlcl9kZiRjb3VudCA9IDAKaW5mZXJfZGYkY29uZCA9IHJlcChuYW1lcyhyZWZvcm1fbGlzdClbMTozXSwgZWFjaCA9IG5yKQpjb2xuYW1lcyhpbmZlcl9kZilbMToyXSA9IGMoIlNPVVJDRSIsICJUQVJHRVQiKQpmb3IoaSBpbiAxOm5yb3coaW5mZXJfZGYpKXsKICB0bXAgPSByZWZvcm1fbGlzdF9pbnRbW2luZmVyX2RmW2ksNF1dXQogIGluZmVyX2RmW2ksM10gPSBkaW0odG1wWyh0bXAkY3QxPT1pbmZlcl9kZltpLDFdICYgdG1wJGN0Mj09aW5mZXJfZGZbaSwyXSkgfAogICAgICAgICAgICAgICAgICAgICAgICAgICAgKHRtcCRjdDI9PWluZmVyX2RmW2ksMV0gJiB0bXAkY3QxPT1pbmZlcl9kZltpLDJdKSxdKVsxXQp9CiMjIG1ha2Ugb25lIHRvIGNvdW50IG92ZXIgYWxsCmluZmVyX2FsbCA9IGRhdGEuZnJhbWUoZXhwYW5kLmdyaWQodW5pcXVlKHJlZm9ybV9saXN0X2ludCRoZWFsdGh5JGN0MSksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVuaXF1ZShyZWZvcm1fbGlzdF9pbnQkaGVhbHRoeSRjdDEpKSkKaW5mZXJfYWxsJGNvdW50ID0gMApjb2xuYW1lcyhpbmZlcl9hbGwpWzE6Ml0gPSBjKCJTT1VSQ0UiLCAiVEFSR0VUIikKcmVmb3JtX2FsbF9pbnQgPSB1bmlxdWUoUmVkdWNlKHJiaW5kLCByZWZvcm1fbGlzdF9pbnQpKQpmb3IoaSBpbiAxOm5yb3coaW5mZXJfYWxsKSl7CiAgaW5mZXJfYWxsW2ksM10gPSBpbmZlcl9hbGxbaSwzXStkaW0odG1wWyhyZWZvcm1fYWxsX2ludCRjdDE9PWluZmVyX2FsbFtpLDFdICYgcmVmb3JtX2FsbF9pbnQkY3QyPT1pbmZlcl9hbGxbaSwyXSkgfAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChyZWZvcm1fYWxsX2ludCRjdDI9PWluZmVyX2FsbFtpLDFdICYgcmVmb3JtX2FsbF9pbnQkY3QxPT1pbmZlcl9hbGxbaSwyXSksXSlbMV0KfQoKaW5mZXJfZGZfbGlzdCA9IGxpc3QoaGVhbHRoeSA9IGluZmVyX2RmW2luZmVyX2RmJGNvbmQ9PSJoZWFsdGh5IixdLAogICAgICAgICAgICAgICAgICAgICBlbWJvbGlzZWQgPSBpbmZlcl9kZltpbmZlcl9kZiRjb25kPT0iZW1ib2xpc2VkIixdLAogICAgICAgICAgICAgICAgICAgICByZWdlbmVyYXRpbmcgPSBpbmZlcl9kZltpbmZlcl9kZiRjb25kPT0icmVnZW5lcmF0aW5nIixdLAogICAgICAgICAgICAgICAgICAgICBhbGwgPSBpbmZlcl9hbGwpCgpuZXRfbmFtZXNfYWxsID0gdChSZWR1Y2UocmJpbmQsIGxhcHBseShpbmZlcl9kZl9saXN0WzE6M10sIGZ1bmN0aW9uKHgpIHRhcHBseSh4JGNvdW50LCB4JFNPVVJDRSwgc3VtKSkpKQpjb2xuYW1lcyhuZXRfbmFtZXNfYWxsKSA9IG5hbWVzKG5ldF9uYW1lc19sKVsxOjNdCm5ldF9uYW1lc19hbGwgPSByZXNoYXBlMjo6bWVsdChuZXRfbmFtZXNfYWxsKQpuZXRfbmFtZXNfYWxsJFZhcjEgPSBmYWN0b3IobmV0X25hbWVzX2FsbCRWYXIxLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IG5ldF9uYW1lc19hbGxbbmV0X25hbWVzX2FsbCRWYXIyPT0iaGVhbHRoeSIsIlZhcjEiXVtvcmRlcihuZXRfbmFtZXNfYWxsW25ldF9uYW1lc19hbGwkVmFyMj09ImhlYWx0aHkiLCJ2YWx1ZSJdLCBkZWNyZWFzaW5nID0gRildKQoKdG90YWxfdW5pcXVlID0gZGF0YS5mcmFtZSh0KHQoUmVkdWNlKHJiaW5kLCBsYXBwbHkoaW5mZXJfZGZfbGlzdFs0XSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uKHgpIHRhcHBseSh4JGNvdW50LCB4JFNPVVJDRSwgc3VtKSkpKSkpCnRvdGFsX3VuaXF1ZSRWYXIxID0gcm93bmFtZXModG90YWxfdW5pcXVlKQpjb2xuYW1lcyh0b3RhbF91bmlxdWUpWzFdID0gInZhbHVlIgp0b3RhbF91bmlxdWUkVmFyMiA9ICJ0b3RhbCB1bmlxdWUiCgpuZXRfbmFtZXNfYWxsJFZhcjEgPSBmYWN0b3IobmV0X25hbWVzX2FsbCRWYXIxLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IHRvdGFsX3VuaXF1ZSRWYXIxW29yZGVyKHRvdGFsX3VuaXF1ZSR2YWx1ZSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZWNyZWFzaW5nID0gRildKQpwbHRfY291bnRzID0gZ2dwbG90KG5ldF9uYW1lc19hbGwsIGFlcyh4ID0gVmFyMSwgeSA9IHZhbHVlKSkrCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKGNvbG91ciA9IFZhcjIpLCBzaXplID0gMS42KSsKICBnZW9tX3BvaW50KGRhdGEgPSB0b3RhbF91bmlxdWUsIG1hcHBpbmcgPSBhZXMoc2hhcGUgPSBWYXIyKSwgc2l6ZSA9IDEuNikrCiAgY29vcmRfZmxpcCgpKwogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gY29sY29uZFsxOjNdKSsKICBzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzID0gYyg0KSkrCiAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwwKSwgbGltaXRzID0gYygwLDMwMDApKSsKICBsYWJzKHkgPSAiVG90YWwgaW50ZXJhY3Rpb25zIiwgeCA9ICJDZWxsIFR5cGUiLCBjb2xvdXIgPSAiQ29uZGl0aW9uIikrCiAgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2xlZ2VuZChvcmRlciA9IDEpLCBzaGFwZSA9IGd1aWRlX2xlZ2VuZChvcmRlciA9IDIsIHRpdGxlID0gTlVMTCkpKwogIHRoZW1lX2J3KCkrCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSAzMCwgdmp1c3QgPSAxLCBoanVzdCA9IDEpLAogICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChjb2xvdXIgPSAiYmxhY2siKSwKICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpLAogICAgICAgIGxlZ2VuZC5tYXJnaW4gPSBtYXJnaW4oMSwgMSwgMSwgMSksCiAgICAgICAgbGVnZW5kLnNwYWNpbmcueCA9IHVuaXQoMC4wNSwgImNtIiksCiAgICAgICAgbGVnZW5kLmRpcmVjdGlvbiA9ICJob3Jpem9udGFsIixsZWdlbmQuYm94ID0gImhvcml6b250YWwiKQpsZWcgPSBjb3dwbG90OjpnZXRfbGVnZW5kKHBsdF9jb3VudHMpCgpwZXJjX2RmID0gZGF0YS5mcmFtZSgiVmFyMSIgPSBuZXRfbmFtZXNfYWxsJFZhcjEsCiAgICAgICAgICAgICAgICAgICAgICJWYXIyIiA9IG5ldF9uYW1lc19hbGwkVmFyMiwKICAgICAgICAgICAgICAgICAgICAgInBlcmMiID0gYyhyZXAoMCwgbGVuZ3RoKHVuaXF1ZShuZXRfbmFtZXNfYWxsJFZhcjEpKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKG5ldF9uYW1lc19hbGwkdmFsdWVbbmV0X25hbWVzX2FsbCRWYXIyPT0iZW1ib2xpc2VkIl0tbmV0X25hbWVzX2FsbCR2YWx1ZVtuZXRfbmFtZXNfYWxsJFZhcjI9PSJoZWFsdGh5Il0pL25ldF9uYW1lc19hbGwkdmFsdWVbbmV0X25hbWVzX2FsbCRWYXIyPT0iaGVhbHRoeSJdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChuZXRfbmFtZXNfYWxsJHZhbHVlW25ldF9uYW1lc19hbGwkVmFyMj09InJlZ2VuZXJhdGluZyJdLW5ldF9uYW1lc19hbGwkdmFsdWVbbmV0X25hbWVzX2FsbCRWYXIyPT0iaGVhbHRoeSJdKS9uZXRfbmFtZXNfYWxsJHZhbHVlW25ldF9uYW1lc19hbGwkVmFyMj09ImhlYWx0aHkiXSkqMTAwKQpwZXJjX2RmJGNvbCA9IGlmZWxzZShwZXJjX2RmJHBlcmM+MCwgImdyZWVuIiwgInJlZCIpCnBlcmNfZGYgPSBwZXJjX2RmW3BlcmNfZGYkVmFyMiE9ImhlYWx0aHkiLF0KCnBlcmNfcGx0X2VtYiA9IGdncGxvdChwZXJjX2RmW3BlcmNfZGYkVmFyMj09ImVtYm9saXNlZCIsXSwgYWVzKHggPSBWYXIxLCB5ID0gcGVyYywgZmlsbCA9IGNvbCkpKwogIGdlb21fY29sKCkrCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiZGVlcHNreWJsdWUxIiwgInJlZDEiKSkrCiAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwwKSwgbGltaXRzID0gYygtMjAsNTUpKSsKICBjb29yZF9mbGlwKCkrCiAgbGFicyh5ID0gIiUgY2hhbmdlXG5lbWJvbGlzZWQgdnMgaGVhbHRoeSIsIHggPSAiQ2VsbCBUeXBlIikrCiAgdGhlbWVfYncoKSsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDMwLCB2anVzdCA9IDEsIGhqdXN0ID0gMSwgY29sb3VyID0gImJsYWNrIiksCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemUgPSA4KSwKICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aWNrcy55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKcGVyY19wbHRfcmVnID0gZ2dwbG90KHBlcmNfZGZbcGVyY19kZiRWYXIyPT0icmVnZW5lcmF0aW5nIixdLCBhZXMoeCA9IFZhcjEsIHkgPSBwZXJjLCBmaWxsID0gY29sKSkrCiAgZ2VvbV9jb2woKSsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJkZWVwc2t5Ymx1ZTEiLCAicmVkMSIpKSsKICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLDApLCBsaW1pdHMgPSBjKC0yMCw1NSkpKwogIGNvb3JkX2ZsaXAoKSsKICBsYWJzKHkgPSAiJSBjaGFuZ2VcbnJlZ2VuZXJhdGluZyB2cyBoZWFsdGh5IiwgeCA9ICJDZWxsIFR5cGUiKSsKICB0aGVtZV9idygpKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMzAsIHZqdXN0ID0gMSwgaGp1c3QgPSAxLCBjb2xvdXIgPSAiYmxhY2siKSwKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpLAogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpY2tzLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQoKY293cGxvdDo6cGxvdF9ncmlkKGNvd3Bsb3Q6OnBsb3RfZ3JpZChwbHRfY291bnRzK3RoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBlcmNfcGx0X2VtYiwgcGVyY19wbHRfcmVnLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuY29sID0gMywgYWxpZ24gPSAiaCIsIGF4aXMgPSAiciIsIHJlbF93aWR0aHMgPSBjKDEsMC41LDAuNSkpLAogICAgICAgICAgICAgICAgICAgbGVnLCBucm93ID0gMiwgcmVsX2hlaWdodHMgPSBjKDEsIDAuMSkpCgpwZGYoImZpZ3VyZV9wYW5lbHNfcmV2MS9maWdfY29tbS9tYWluRmlnX2NvdW50c0NvbmRfbWlkLnBkZiIsIGhlaWdodCA9IDMuMzUsIHdpZHRoID0gNS41KQpjb3dwbG90OjpwbG90X2dyaWQoY293cGxvdDo6cGxvdF9ncmlkKHBsdF9jb3VudHMrdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGVyY19wbHRfcmVnLCBwZXJjX3BsdF9lbWIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5jb2wgPSAzLCBhbGlnbiA9ICJoIiwgYXhpcyA9ICJyIiwgcmVsX3dpZHRocyA9IGMoMSwwLjQsMC40KSksCiAgICAgICAgICAgICAgICAgICBsZWcsIG5yb3cgPSAyLCByZWxfaGVpZ2h0cyA9IGMoMSwgMC4xKSkKZGV2Lm9mZigpCmBgYAoKCgoKIyBQYW5lbHMgY2lycmhvc2lzClVNQVAgSW1tdW5lIGNlbGxzCgpgYGB7ciwgZmlnLmhlaWdodD0yLCBmaWcud2lkdGg9Mi43NX0KaW1tX2RmID0gcmVhZFJEUygicmVzdWx0cy9jaXJyaG9zaXMvdW1hcF9pbW1fZGYuUkRTIikKCmNvbHMgPSBNZXRCcmV3ZXI6Om1ldC5icmV3ZXIoIkVneXB0IiwgbGVuZ3RoKHVuaXF1ZShpbW1fZGYkc2ltcF9hbm5vdCkpKQpuYW1lcyhjb2xzKSA9IHVuaXF1ZShpbW1fZGYkc2ltcF9hbm5vdCkKY29sc1siTm9uIGFubm90YXRlZCBjZWxscyJdID0gImdyZXk4MCIKCmltbV9kZiA9IGltbV9kZltzYW1wbGUoMTpucm93KGltbV9kZiksIG5yb3coaW1tX2RmKSwgcmVwbGFjZSA9IEYpLF0KcGx0ID0gZ2dwbG90KCkrCiAgZ2VvbV9wb2ludChhZXMoeCA9IFVNQVBfMSwgeSA9IFVNQVBfMiwgY29sb3VyID0gc2ltcF9hbm5vdCksIAogICAgICAgICAgICAgaW1tX2RmLCBzaXplID0gMC4yKSsKICBndWlkZXMoY29sb3VyID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZSA9IDMpKSkrCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjb2xzW29yZGVyKG5hbWVzKGNvbHMpKV0pKwogIHRoZW1lX3ZvaWQoKSsKICB0aGVtZShhc3BlY3QucmF0aW8gPSAxLAogICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA3KSwKICAgICAgICBsZWdlbmQua2V5LnNpemUgPSB1bml0KDAuNCwgImNtIiksCiAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQoKcGRmKCJmaWd1cmVfcGFuZWxzX3JldjEvZmlnX2Npci9hbGxfaW1tdW5lX3VtYXAucGRmIiwgaGVpZ2h0ID0gMi4yLCB3aWR0aCA9IDQuMikKcHJpbnQocGx0KQpkZXYub2ZmKCkKYGBgCgpVTUFQIE1vbm8vTWFjIGNlbGxzCgpgYGB7ciwgZmlnLmhlaWdodD0yLCBmaWcud2lkdGg9Mi43NX0KbV9kZiA9IHJlYWRSRFMoZmlsZSA9ICJyZXN1bHRzL2NpcnJob3Npcy91bWFwX21fZGYuUkRTIikKCmNvbHMgPSBNZXRCcmV3ZXI6Om1ldC5icmV3ZXIoIktsaW10IiwgbGVuZ3RoKHVuaXF1ZShtX2RmJGFsbF9hbm5vdCkpKQpuYW1lcyhjb2xzKSA9IHVuaXF1ZShtX2RmJGFsbF9hbm5vdCkKCm1fZGYgPSBtX2RmW3NhbXBsZSgxOm5yb3cobV9kZiksIG5yb3cobV9kZiksIHJlcGxhY2UgPSBGKSxdCnBsdCA9IGdncGxvdCgpKwogIGdlb21fcG9pbnQoYWVzKHggPSBVTUFQXzEsIHkgPSBVTUFQXzIsIGNvbG91ciA9IGFsbF9hbm5vdCksIAogICAgICAgICAgICAgbV9kZiwgc2l6ZSA9IDAuMikrCiAgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KHNpemUgPSAzKSkpKwogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gY29sc1tvcmRlcihuYW1lcyhjb2xzKSldKSsKICB0aGVtZV92b2lkKCkrCiAgdGhlbWUoYXNwZWN0LnJhdGlvID0gMSwKICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gNiksCiAgICAgICAgbGVnZW5kLmtleS5zaXplID0gdW5pdCgwLjQsICJjbSIpLAogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKCnBkZigiZmlndXJlX3BhbmVsc19yZXYxL2ZpZ19jaXIvYWxsX21vbm9fdW1hcC5wZGYiLCBoZWlnaHQgPSAyLjIsIHdpZHRoID0gNC4yKQpwcmludChwbHQpCmRldi5vZmYoKQpgYGAKClVNQVAgVC9OSyBjZWxscwoKYGBge3J9CnRfZGYgPSByZWFkUkRTKGZpbGUgPSAicmVzdWx0cy9jaXJyaG9zaXMvdW1hcF90X2RmLlJEUyIpCgpjb2xzID0gTWV0QnJld2VyOjptZXQuYnJld2VyKCJKdWFyZXoiLCBsZW5ndGgodW5pcXVlKHRfZGYkYWxsX2Fubm90KSkpCm5hbWVzKGNvbHMpID0gdW5pcXVlKHRfZGYkYWxsX2Fubm90KQoKdF9kZiA9IHRfZGZbc2FtcGxlKDE6bnJvdyh0X2RmKSwgbnJvdyh0X2RmKSwgcmVwbGFjZSA9IEYpLF0KcGx0ID0gZ2dwbG90KCkrCiAgZ2VvbV9wb2ludChhZXMoeCA9IFVNQVBfMSwgeSA9IFVNQVBfMiwgY29sb3VyID0gYWxsX2Fubm90KSwgCiAgICAgICAgICAgICB0X2RmLCBzaXplID0gMC4yKSsKICBndWlkZXMoY29sb3VyID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZSA9IDMpKSkrCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjb2xzW29yZGVyKG5hbWVzKGNvbHMpKV0pKwogIHRoZW1lX3ZvaWQoKSsKICB0aGVtZShhc3BlY3QucmF0aW8gPSAxLAogICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA2KSwKICAgICAgICBsZWdlbmQua2V5LnNpemUgPSB1bml0KDAuMzc1LCAiY20iKSwKICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCgpwZGYoImZpZ3VyZV9wYW5lbHNfcmV2MS9maWdfY2lyL2FsbF90bmtfdW1hcC5wZGYiLCBoZWlnaHQgPSAyLjIsIHdpZHRoID0gNC4yKQpwcmludChwbHQpCmRldi5vZmYoKQpgYGAKCk1hcmtlcnMgbXllbG9pZCBjZWxscwoKYGBge3J9Cm1hdF9tID0gcmVhZFJEUyhmaWxlID0gInJlc3VsdHMvY2lycmhvc2lzL21hdF9teWVsb2lkX21hcmtlcnMuUkRTIikKCmNvbHNfcGFsID0gY29sb3JSYW1wUGFsZXR0ZShyZXYoYnJld2VyLnBhbChuID0gOSwgbmFtZSA9ICJSZEJ1IikpKSgxMDApCgpwZGYoImZpZ3VyZV9wYW5lbHNfcmV2MS9maWdfY2lyL2hlYXRfbWtfbXllLnBkZiIsIGhlaWdodCA9IDIuMiwgd2lkdGggPSA2LjMpCnBoZWF0bWFwOjpwaGVhdG1hcChtYXRfbSwgY2x1c3RlcmluZ19tZXRob2QgPSAid2FyZC5EIiwgY29sb3IgPSBjb2xzX3BhbCwKICAgICAgICAgICAgICAgICAgIHRyZWVoZWlnaHRfY29sID0gMCwgdHJlZWhlaWdodF9yb3cgPSAyMCwgZm9udHNpemUgPSA2LjMpCmRldi5vZmYoKQpgYGAKCk1hcmtlcnMgbHltcGhvaWQgY2VsbHMKCmBgYHtyfQptYXRfbCA9IHJlYWRSRFMoInJlc3VsdHMvY2lycmhvc2lzL21hdF9seW1waG9pZF9tYXJrZXJzLlJEUyIpCgpjb2xzX3BhbCA9IGNvbG9yUmFtcFBhbGV0dGUocmV2KGJyZXdlci5wYWwobiA9IDksIG5hbWUgPSAiUmRCdSIpKSkoMTAwKQoKcGRmKCJmaWd1cmVfcGFuZWxzX3JldjEvZmlnX2Npci9oZWF0X21rX2x5bS5wZGYiLCBoZWlnaHQgPSAyLjIsIHdpZHRoID0gNi4zKQpwaGVhdG1hcDo6cGhlYXRtYXAobWF0X2wsIGNsdXN0ZXJpbmdfbWV0aG9kID0gIndhcmQuRCIsIGNvbG9yID0gY29sc19wYWwsCiAgICAgICAgICAgICAgICAgICB0cmVlaGVpZ2h0X2NvbCA9IDAsIHRyZWVoZWlnaHRfcm93ID0gMjAsIGZvbnRzaXplID0gNi4zKQpkZXYub2ZmKCkKYGBgCgpQcm9wb3J0aW9ucyBpbW11bmUgY2VsbHMKCmBgYHtyfQppbW1fcHJvcHMgPSByZWFkUkRTKGZpbGUgPSAicmVzdWx0cy9jaXJyaG9zaXMvaW1tX3Byb3BzX2RhdC5SRFMiKQppbW1fcHZhbHMgPSByZWFkUkRTKCJyZXN1bHRzL2NpcnJob3Npcy9pbW1fcHJvcHNfcHZhbC5SRFMiKQoKcGx0ID0gZ2dwbG90KGltbV9wcm9wcywgYWVzKHggPSBDb25kaXRpb24sIHkgPSBGcmVxLCBncm91cCA9IENvbmRpdGlvbiwgY29sb3VyID0gQ29uZGl0aW9uKSkrCiAgZmFjZXRfd3JhcCh+VmFyMSwgc2NhbGVzID0gImZyZWUiKSsKICBnZW9tX2ppdHRlcihwb3NpdGlvbiA9IHBvc2l0aW9uX2ppdHRlcmRvZGdlKGppdHRlci53aWR0aCA9IDAuMywgZG9kZ2Uud2lkdGggPSAxKSkrCiAgc3RhdF9zdW1tYXJ5KGZ1bi5kYXRhID0gbWVhbl9zZSwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDEpLCAKICAgICAgICAgICAgICAgYWxwaGEgPSAwLjM1LCBjb2xvdXIgPSAiYmxhY2siKSsKICB0aGVtZV9idygpKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKCgpjb2xuYW1lcyhpbW1fcHZhbHMpWzFdID0gImVtYm9saXplZCIKCmltbV9wcm9wcyRDb25kaXRpb25baW1tX3Byb3BzJENvbmRpdGlvbj09ImVtYm9saXNlZCJdID0gImVtYm9saXplZCIKaW1tX3Byb3BzJENvbmRpdGlvbiA9IGZhY3RvcihpbW1fcHJvcHMkQ29uZGl0aW9uLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJoZWFsdGh5IiwgInJlZ2VuZXJhdGluZyIsICJlbWJvbGl6ZWQiKSkKCnB2YWxfcG9zID0gaW1tX3Byb3BzICU+JQogIGdyb3VwX2J5KENvbmRpdGlvbiwgVmFyMSkgJT4lCiAgc3VtbWFyaXNlX2F0KHZhcnMoIkZyZXEiKSwgbWVhbikKcHZhbF9wb3MkcG9zeSA9IHB2YWxfcG9zJEZyZXEqMS4wMgpwdmFsX3BvcyRwb3N4ID0gYXMubnVtZXJpYyhwdmFsX3BvcyRDb25kaXRpb24pKzAuMwpwdmFsX3BvcyA9IHB2YWxfcG9zW3B2YWxfcG9zJENvbmRpdGlvbiE9ImhlYWx0aHkiLF0KcHZhbF9wb3MkcHZhbCA9IGRpYWcoYXMubWF0cml4KGltbV9wdmFsc1twdmFsX3BvcyRWYXIxLGFzLmNoYXJhY3RlcihwdmFsX3BvcyRDb25kaXRpb24pXSkpCnB2YWxfcG9zJGlzc2lnID0gaWZlbHNlKHB2YWxfcG9zJHB2YWw8PTAuMDUsICIqIiwgIiIpCgpwbHQgPSBnZ3Bsb3QoKSsKICBmYWNldF93cmFwKH5WYXIxLCBzY2FsZXMgPSAiZnJlZSIpKwogIGdlb21faml0dGVyKGRhdGEgPSBpbW1fcHJvcHMsIG1hcHBpbmcgPSBhZXMoeCA9IENvbmRpdGlvbiwgeSA9IEZyZXEsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXAgPSBDb25kaXRpb24sIGNvbG91ciA9IENvbmRpdGlvbiksCiAgICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9qaXR0ZXJkb2RnZShqaXR0ZXIud2lkdGggPSAwLjMsIGRvZGdlLndpZHRoID0gMSksIHNpemUgPSAwLjUpKwogIHN0YXRfc3VtbWFyeShkYXRhID0gaW1tX3Byb3BzLCBtYXBwaW5nID0gYWVzKHggPSBDb25kaXRpb24sIHkgPSBGcmVxLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwID0gQ29uZGl0aW9uLCBjb2xvdXIgPSBDb25kaXRpb24pLAogICAgICAgICAgICAgICBmdW4uZGF0YSA9IG1lYW5fc2UsIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAxKSwgCiAgICAgICAgICAgICAgIGFscGhhID0gMC42LCBjb2xvdXIgPSAiYmxhY2siLCBzaXplID0gMC4yNSkrCiAgZ2VvbV90ZXh0KGRhdGEgPSBwdmFsX3BvcywgbWFwcGluZyA9IGFlcyh4ID0gcG9zeCwgeSA9IHBvc3ksIGxhYmVsID0gaXNzaWcpLCBzaXplID0gNCkrCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjb2xjb25kLCBkcm9wID0gVCwgbGltaXRzID0gbmFtZXMoY29sY29uZClbYygxLDIsNCldKSsKICBzY2FsZV94X2Rpc2NyZXRlKGxhYmVscyA9IGMoIkgiLCAiUiIsICJFIikpKwogIGxhYnMoeSA9ICJwcm9wb3J0aW9uICUgKGltbXVuZSkiKSsKICB0aGVtZV9idygpKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwKICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA2LCBjb2xvdXIgPSAiYmxhY2siKSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gNiwgY29sb3VyID0gImJsYWNrIiksCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYsIGNvbG91ciA9ICJibGFjayIpLAogICAgICAgIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYpLAogICAgICAgIHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ3aGl0ZSIpLAogICAgICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvci54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBhbmVsLmdyaWQubWFqb3IueSA9IGVsZW1lbnRfbGluZShzaXplID0gMC4zLCBjb2xvdXIgPSAiZ3JleTcwIikpCgojcGRmKCJmaWd1cmVfcGFuZWxzX3JldjEvZmlnX2Npci9pbW11bmVfYWxsX3Byb3AucGRmIiwgaGVpZ2h0ID0gNy41LCB3aWR0aCA9IDExLjUpCnByaW50KHBsdCkKI2Rldi5vZmYoKQoKcGRmKCJmaWd1cmVfcGFuZWxzX3JldjEvZmlnX2Npci9pbW11bmVfYWxsX3Byb3BfcmVzaXplZC5wZGYiLCBoZWlnaHQgPSA1LjUsIHdpZHRoID0gNykKcHJpbnQocGx0KQpkZXYub2ZmKCkKYGBgCgpQcm9wb3J0aW9ucyBlbmRvdGhlbGlhbCBjZWxscwoKYGBge3J9CmVuZF9wcm9wcyA9IHJlYWRSRFMoZmlsZSA9ICJyZXN1bHRzL2NpcnJob3Npcy9lbmRfcHJvcHNfZGF0LlJEUyIpCmVuZF9wdmFscyA9IHJlYWRSRFMoInJlc3VsdHMvY2lycmhvc2lzL2VuZF9wcm9wc19wdmFsLlJEUyIpCmNvbG5hbWVzKGVuZF9wdmFscylbMV0gPSAiZW1ib2xpemVkIgoKZW5kX3Byb3BzJENvbmRpdGlvbltlbmRfcHJvcHMkQ29uZGl0aW9uPT0iZW1ib2xpc2VkIl0gPSAiZW1ib2xpemVkIgplbmRfcHJvcHMkQ29uZGl0aW9uID0gZmFjdG9yKGVuZF9wcm9wcyRDb25kaXRpb24sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoImhlYWx0aHkiLCAicmVnZW5lcmF0aW5nIiwgImVtYm9saXplZCIpKQoKcHZhbF9wb3MgPSBlbmRfcHJvcHMgJT4lCiAgZ3JvdXBfYnkoQ29uZGl0aW9uLCBWYXIxKSAlPiUKICBzdW1tYXJpc2VfYXQodmFycygiRnJlcSIpLCBtZWFuKQpwdmFsX3BvcyRwb3N5ID0gcHZhbF9wb3MkRnJlcSoxLjAyCnB2YWxfcG9zJHBvc3ggPSBhcy5udW1lcmljKHB2YWxfcG9zJENvbmRpdGlvbikrMC4yCnB2YWxfcG9zID0gcHZhbF9wb3NbcHZhbF9wb3MkQ29uZGl0aW9uIT0iaGVhbHRoeSIsXQpwdmFsX3BvcyRwdmFsID0gZGlhZyhhcy5tYXRyaXgoZW5kX3B2YWxzW3B2YWxfcG9zJFZhcjEsYXMuY2hhcmFjdGVyKHB2YWxfcG9zJENvbmRpdGlvbildKSkKcHZhbF9wb3MkaXNzaWcgPSBpZmVsc2UocHZhbF9wb3MkcHZhbDw9MC4wNSwgIioiLCAiIikKCnBsdCA9IGdncGxvdCgpKwogIGZhY2V0X3dyYXAoflZhcjEsIHNjYWxlcyA9ICJmcmVlIikrCiAgZ2VvbV9qaXR0ZXIoZGF0YSA9IGVuZF9wcm9wcywgbWFwcGluZyA9IGFlcyh4ID0gQ29uZGl0aW9uLCB5ID0gRnJlcSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncm91cCA9IENvbmRpdGlvbiwgY29sb3VyID0gQ29uZGl0aW9uKSwKICAgICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2ppdHRlcmRvZGdlKGppdHRlci53aWR0aCA9IDAuMywgZG9kZ2Uud2lkdGggPSAxKSkrCiAgc3RhdF9zdW1tYXJ5KGRhdGEgPSBlbmRfcHJvcHMsIG1hcHBpbmcgPSBhZXMoeCA9IENvbmRpdGlvbiwgeSA9IEZyZXEsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXAgPSBDb25kaXRpb24sIGNvbG91ciA9IENvbmRpdGlvbiksCiAgICAgICAgICAgICAgIGZ1bi5kYXRhID0gbWVhbl9zZSwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDEpLCAKICAgICAgICAgICAgICAgYWxwaGEgPSAwLjYsIGNvbG91ciA9ICJibGFjayIpKwogIGdlb21fdGV4dChkYXRhID0gcHZhbF9wb3MsIG1hcHBpbmcgPSBhZXMoeCA9IHBvc3gsIHkgPSBwb3N5LCBsYWJlbCA9IGlzc2lnKSwgc2l6ZSA9IDYpKwogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gY29sY29uZCwgZHJvcCA9IFQsIGxpbWl0cyA9IG5hbWVzKGNvbGNvbmQpW2MoMSwyLDQpXSkrCiAgbGFicyh5ID0gIiUgKGVuZG90aGVsaWFsKSIpKwogIHRoZW1lX2J3KCkrCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDcuNSwgY29sb3VyID0gImJsYWNrIiksCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDcsIGNvbG91ciA9ICJibGFjayIpLAogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSA2LCBjb2xvdXIgPSAiYmxhY2siKSwKICAgICAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA3KSwKICAgICAgICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAid2hpdGUiKSwKICAgICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBhbmVsLmdyaWQubWFqb3IueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwYW5lbC5ncmlkLm1ham9yLnkgPSBlbGVtZW50X2xpbmUoc2l6ZSA9IDAuMywgY29sb3VyID0gImdyZXk3MCIpKQoKcGRmKCJmaWd1cmVfcGFuZWxzX3JldjEvZmlnX2Npci9lbmRvX2FsbF9wcm9wLnBkZiIsIGhlaWdodCA9IDUsIHdpZHRoID0gNy44KQpwcmludChwbHQpCmRldi5vZmYoKQpgYGAKCk1QIHNpZ25hdHVyZXMKCmBgYHtyfQptcF9zaWdfZGYgPSByZWFkUkRTKGZpbGUgPSAicmVzdWx0cy9jaXJyaG9zaXMvbW9ub19jaXJyX2N0X3NpZ25hdHVyZXMuUkRTIikKCnBsb3RfZGYgPSByZXNoYXBlMjo6bWVsdChtcF9zaWdfZGYpCnBsb3RfZGYkQ29uZGl0aW9uW3Bsb3RfZGYkQ29uZGl0aW9uPT0iZW1ib2xpc2VkIl0gPSAiZW1ib2xpemVkIgpwbG90X2RmJENvbmRpdGlvbiA9IGZhY3RvcihwbG90X2RmJENvbmRpdGlvbiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoImhlYWx0aHkiLCJyZWdlbmVyYXRpbmciLCJlbWJvbGl6ZWQiKSkKc3ViX3Bsb3RfZGYgPSBwbG90X2RmW3Bsb3RfZGYkdmFyaWFibGUgJWluJSBjKCJjaXJyX2N0X01Qc180IiwiY2lycl9jdF9NUHNfNSIpLF0Kc3ViX3Bsb3RfZGYkdmFyaWFibGUgPSBnc3ViKCJjaXJyX2N0X01Qc180IiwgIlNBTWFjICgxKSIsIHN1Yl9wbG90X2RmJHZhcmlhYmxlKQpzdWJfcGxvdF9kZiR2YXJpYWJsZSA9IGdzdWIoImNpcnJfY3RfTVBzXzUiLCAiU0FNYWMgKDIpIiwgc3ViX3Bsb3RfZGYkdmFyaWFibGUpCgpwbHQgPSBnZ3Bsb3Qoc3ViX3Bsb3RfZGYsIGFlcyh4ID0gbW9ub19hbm5vdCwgeSA9IHZhbHVlLCBmaWxsID0gQ29uZGl0aW9uKSkrCiAgZmFjZXRfZ3JpZCh2YXJpYWJsZX5tb25vX2Fubm90LCBzY2FsZXMgPSAiZnJlZSIpKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV0eXBlID0gImRhc2hlZCIsIHNpemUgPSAwLjMpKwogIGdlb21fdmlvbGluKHNjYWxlID0gImNvdW50IikrCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY29sY29uZCwgZHJvcCA9IFQsIGxpbWl0cyA9IG5hbWVzKGNvbGNvbmQpW2MoMSwyLDQpXSkrCiAgdGhlbWVfY2xhc3NpYygpKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpY2tzLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYsIGNvbG91ciA9ICJibGFjayIpLAogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gNi41KSwKICAgICAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA3KSwKICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImJsYWNrIiwgZmlsbCA9IE5BKSwKICAgICAgICBheGlzLmxpbmUgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gYygwLjA0OCwgMC44NjUpLAogICAgICAgIGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGxlZ2VuZC5rZXkuc2l6ZSA9IHVuaXQoMC4zLCAiY20iKSwKICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gNi41KSwKICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDcpKQoKcGRmKCJmaWd1cmVfcGFuZWxzX3JldjEvZmlnX2Npci9tcF9zaWdfdmlvLnBkZiIsIGhlaWdodCA9IDMsIHdpZHRoID0gMTAuMzUpCnByaW50KHBsdCkKZGV2Lm9mZigpCmBgYAoKRW5kb3RoZWxpYWwgc2lnbmF0dXJlcwoKYGBge3J9CmVuZF9zaWdfZGYgPSByZWFkUkRTKGZpbGUgPSAicmVzdWx0cy9jaXJyaG9zaXMvZW5kb19jaXJyX2N0X3NpZ25hdHVyZXMuUkRTIikKCnBsb3RfZGYgPSByZXNoYXBlMjo6bWVsdChlbmRfc2lnX2RmKQpwbG90X2RmJENvbmRpdGlvbltwbG90X2RmJENvbmRpdGlvbj09ImVtYm9saXNlZCJdID0gImVtYm9saXplZCIKcGxvdF9kZiRDb25kaXRpb25bcGxvdF9kZiRDb25kaXRpb249PSJlbWJvbGlzZWQiXSA9ICJlbWJvbGl6ZWQiCnBsb3RfZGYkQ29uZGl0aW9uID0gZmFjdG9yKHBsb3RfZGYkQ29uZGl0aW9uLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygiaGVhbHRoeSIsInJlZ2VuZXJhdGluZyIsImVtYm9saXplZCIpKQpzdWJfcGxvdF9kZiA9IHBsb3RfZGZbcGxvdF9kZiR2YXJpYWJsZSAlaW4lIGMoImNpcnJfY3RfRW5kb3RoZWxpYV82IiwiY2lycl9jdF9FbmRvdGhlbGlhXzciKSxdCnN1Yl9wbG90X2RmJHZhcmlhYmxlID0gZ3N1YigiY2lycl9jdF9FbmRvdGhlbGlhXzYiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTQUVuZG90aGVsaWFsICgxKSIsIHN1Yl9wbG90X2RmJHZhcmlhYmxlKQpzdWJfcGxvdF9kZiR2YXJpYWJsZSA9IGdzdWIoImNpcnJfY3RfRW5kb3RoZWxpYV83IiwgIlNBRW5kb3RoZWxpYWwgKDIpIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1Yl9wbG90X2RmJHZhcmlhYmxlKQoKcGx0ID0gZ2dwbG90KHN1Yl9wbG90X2RmLCBhZXMoeCA9IGVuZG9fc2ltcCwgeSA9IHZhbHVlLCBmaWxsID0gQ29uZGl0aW9uKSkrCiAgZmFjZXRfZ3JpZCh2YXJpYWJsZX5lbmRvX3NpbXAsIHNjYWxlcyA9ICJmcmVlIikrCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAiZGFzaGVkIiwgc2l6ZSA9IDAuMykrCiAgZ2VvbV92aW9saW4oc2NhbGUgPSAiY291bnQiKSsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjb2xjb25kLCBkcm9wID0gVCwgbGltaXRzID0gbmFtZXMoY29sY29uZClbYygxLDIsNCldKSsKICB0aGVtZV9jbGFzc2ljKCkrCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gNiwgY29sb3VyID0gImJsYWNrIiksCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSA2LjUpLAogICAgICAgIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDcpLAogICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiYmxhY2siLCBmaWxsID0gTkEpLAogICAgICAgIGF4aXMubGluZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwKICAgICAgICBsZWdlbmQuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBsZWdlbmQubWFyZ2luID0gbWFyZ2luKDAsMCwwLDApLAogICAgICAgIGxlZ2VuZC5rZXkuc2l6ZSA9IHVuaXQoMC4zLCAiY20iKSwKICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gNi41KSwKICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDcpKQoKcGRmKCJmaWd1cmVfcGFuZWxzX3JldjEvZmlnX2Npci9lbmRvX3NpZ192aW8ucGRmIiwgaGVpZ2h0ID0gMi44LCB3aWR0aCA9IDExKQpwcmludChwbHQpCmRldi5vZmYoKQpgYGAKCkhlcGF0b2N5dGUgc2lnbmF0dXJlcwoKYGBge3J9CnNjb3Jlc19kZiA9IHJlYWRSRFMoInJlc3VsdHMvY2lycmhvc2lzL2RzX2hlcF9zY29yZWREZXZfZGYuUkRTIikKc2NvcmVzX2RmJENvbmRpdGlvbltzY29yZXNfZGYkQ29uZGl0aW9uPT0iZW1ib2xpc2VkIl0gPSAiZW1ib2xpemVkIgoKcGx0ID0gZ2dwbG90KHNjb3Jlc19kZiwgYWVzKHggPSBjaXJyX2ZldGFsXzMsIHkgPSBjaXJyX2ZldGFsXzYsIGNvbG91ciA9IENvbmRpdGlvbikpKwogIGZhY2V0X3dyYXAofnN1YnBvcHMpKwogIGdlb21fZGVuc2l0eV8yZChzaXplID0gMC4zKSsKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGNvbGNvbmQsIGRyb3AgPSBULCBsaW1pdHMgPSBuYW1lcyhjb2xjb25kKVtjKDEsMiw0KV0pKwogIGxhYnMoeCA9ICJBZHVsdCBoZXBhdG9jeXRlIHNpZ25hdHVyZSIsIHkgPSAiRmV0YWwgaGVwYXRvY3l0ZSBzaWduYXR1cmUiKSsKICB0aGVtZV9jbGFzc2ljKCkrCiAgdGhlbWUoYXNwZWN0LnJhdGlvID0gMSwKICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoY29sb3VyID0gImJsYWNrIiwgc2l6ZSA9IDYpLAogICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoY29sb3VyID0gImJsYWNrIiwgc2l6ZSA9IDYpLAogICAgICAgIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDcpLAogICAgICAgIGxlZ2VuZC5rZXkuc2l6ZSA9IHVuaXQoMC4zLCAiY20iKSwKICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gNi41KSwKICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDcpKQoKcGRmKCJmaWd1cmVfcGFuZWxzX3JldjEvZmlnX2Npci9oZXBfZGV2X3NpZ19kZW5zaXR5LnBkZiIsIGhlaWdodCA9IDEuNSwgd2lkdGggPSA0LjUpCnByaW50KHBsdCkKZGV2Lm9mZigpCmBgYAoKCgoK